it-swarm.com.de

Deaktivieren einer Schaltfläche in Vanilla JavaScript und in jQuery

Vanille JavaScript

In Vanilla JavaScript kann eine Schaltfläche mit der folgenden Anweisung problemlos aktiviert und deaktiviert werden:

button.disabled = state;

Dies funktioniert sowohl, wenn Menschen versuchen, auf eine Schaltfläche zu klicken, als auch, wenn Tasten programmgesteuert angeklickt werden:

var button = document.getElementById('myButton');

button.addEventListener('click', function() {
    alert('world');
});

button.disabled = true;
button.click(); // No output
button.disabled = false;
button.click(); // Output : "Hello" and "world
button.disabled = true;
button.click(); // No output
<input type="button" id="myButton" value="button" onClick="alert('Hello')"/>

Dies funktioniert auch bei Verwendung der MouseEvent-Schnittstelle:

var button = document.getElementById('myButton');

var click = new MouseEvent("click", {
    "view": window
});

button.addEventListener('click', function() {
    alert('world');
});

button.disabled = true;
button.dispatchEvent(click); // No output
button.disabled = false;
button.dispatchEvent(click); // Output : "Hello" and "world
button.disabled = true;
button.dispatchEvent(click); // No output
<input type="button" id="myButton" value="button" onClick="alert('Hello')"/>


jQuery

Ich kann jedoch mit jQuery anscheinend nicht dasselbe tun:

var button = $("#myButton");

button.on("click", function() {
    alert("world");
});

button.prop("disabled", true);
button.click(); // Output : "world" and "Hello"
button.prop("disabled", false);
button.click(); // Output : "world" and "Hello"
button.prop("disabled", true);
button.click(); // Output : "world" and "Hello"
<script src="https://code.jquery.com/jquery-1.12.2.min.js"></script>
<input type="button" id="myButton" value="button" onClick="alert('Hello')"/>

Sowohl button.prop("disabled", true); als auch button.attr("disabled", true); ändern einfach die disabled-Eigenschaft des button-Elements, ohne jedoch das eigentliche Klickereignis zu deaktivieren. Das bedeutet, dass Ereignisse ausgelöst werden, wenn button.click(); aufgerufen wird, auch wenn die Schaltfläche deaktiviert ist!

Außerdem werden "world" und "Hello" in der falschen Reihenfolge ausgegeben.

Der einfachste Code, mit dem ich das Verhalten der Vanilla JavaScript-Versionen nachahmen könnte, ist folgender:

var button = $("#myButton");

button.on("click", function() {
    alert("world");
});

button.disable = (function() {
    var onclick = null;
    var click = [];
    return function(state) {
        if(state) {
            this.prop('disabled', true);
            if(this.prop('onclick') !== null) {
                onclick = this.prop('onclick');
                this.prop('onclick', null);
            }
            var listeners = $._data(this.get()[0], "events");
            listeners = typeof listeners === 'undefined' ? [] : listeners['click'];
            if(listeners && listeners.length > 0) {
                for(var i = 0; i < listeners.length; i++) {
                    click.Push(listeners[i].handler);
                }
                this.off('click');
            }
        } else {
            this.removeProp('disabled');
            if(onclick !== null) {
                this.prop('onclick', onclick);
                onclick = null;
            }
            if(click.length > 0) {
                this.off('click');
                for(var i = 0; i < click.length; i++) {
                    this.on("click", click[i]);
                }
                click = [];
            }
        }
    }
})();

button.disable(true);
button.click(); // No output
button.disable(false);
button.click(); // Output : "Hello" and "world
button.disable(true);
button.click(); // No output
<script src="https://code.jquery.com/jquery-1.12.2.min.js"></script>
<input type="button" id="myButton" value="button" onClick="alert('Hello')"/>

Das ist natürlich lächerlich verschlungener und "hacky" Code, um etwas zu erreichen, das so einfach ist wie das Deaktivieren einer Taste.


Meine Fragen

  • Warum deaktiviert jQuery im Gegensatz zu Vanilla JS nicht die Ereignisse, wenn eine Schaltfläche deaktiviert wird?
  • Ist dies ein Fehler oder eine Funktion in jQuery?
  • Gibt es etwas, das ich übersehe?
  • Gibt es eine einfachere Methode, um das erwartete Verhalten in jQuery zu ermitteln?
16
John Slegers

Um das erwartete Ergebnis zu erzielen, können Sie .isTrigger innerhalb des durch jQuery ausgelösten click-Handlers verwenden, um zu bestimmen, ob das Ereignis durch javascript ausgelöst wird, und keine Benutzeraktion. 

Definieren Sie den Attributereignislistener als benannte Funktion, wobei this an die disabled-Eigenschaft unter if-Bedingung übergeben werden kann, wenn alert() aufgerufen wird oder nicht aufgerufen wird.

Verwenden Sie .attr("disabled", "disabled"), um disabled am Element festzulegen, .removeAttr("disabled"), um das Attribut zu entfernen. .attr("onclick", null), um das Ereignisattribut zu entfernen onclick Handler; .attr("onclick", "handleClick(true)"), um das Ereignisattribut zurückzusetzen.

<script src="https://code.jquery.com/jquery-3.1.0.js"></script>

<input type="button" id="myButton" value="button" onclick="handleClick(this)" />
<script>
  function handleClick(el) {
    if (el.disabled !== "disabled")
      alert("Hello")
  }
  var button = $("#myButton");

  button.on("click", function(e) {
    console.log(e);
    if (e.isTrigger !== 3 && !e.target.disabled)
      alert("world");
  });

  button.attr("disabled", "disabled");
  button.attr("onclick", null);
  button.click(); // no output
  
  setTimeout(function() {
    button.removeAttr("disabled");
    button.attr("onclick", "handleClick(button[0])");
    button.click(); // Output : "world" and "Hello"
    // click button during 9000 between `setTimeout` calls
    // to call both jQuery event and event attribute
  }, 1000);

  setTimeout(function() {
    button.attr("disabled", "disabled");
    button.attr("onclick", null);
    button.click(); // no output
  }, 10000);
  
</script>

2
guest271314

Wenn Sie einen Blick auf jquery-1.12.4.js auf diese Zeilen werfen:

handlers: function( event, handlers ) {
    var i, matches, sel, handleObj,
        handlerQueue = [],
        delegateCount = handlers.delegateCount,
        cur = event.target;

    // Support (at least): Chrome, IE9
    // Find delegate handlers
    // Black-hole SVG <use> instance trees (#13180)
    //
    // Support: Firefox<=42+
    // Avoid non-left-click in FF but don't block IE radio events (#3861, gh-2343)
    if ( delegateCount && cur.nodeType &&
        ( event.type !== "click" || isNaN( event.button ) || event.button < 1 ) ) {

        /* jshint eqeqeq: false */
        for ( ; cur != this; cur = cur.parentNode || this ) {
            /* jshint eqeqeq: true */

            // Don't check non-elements (#13208)
            // Don't process clicks on disabled elements (#6911, #8165, #11382, #11764)
            if ( cur.nodeType === 1 && ( cur.disabled !== true || event.type !== "click" ) ) {

Je nach Delegierungstyp wird eine unterschiedliche Behandlung von Ereignissen angezeigt:

$(document).on("click", '#btn', function() {
  console.log("world");
});


$(function () {
  $('#btnToggle').on('click', function(e) {
    $('#btn').prop('disabled', !$('#btn').prop('disabled'));
  });
  
  
  $('#btnTestClick').on('click', function(e) {
    $('#btn').click();
  });
});
<script src="https://code.jquery.com/jquery-1.12.4.min.js"></script>

<button id="btn">Click  Me</button>
<button id="btnToggle">Enable/Disable button</button>
<button id="btnTestClick">Test Click</button>

Natürlich, wenn Sie das Ereignis anhängen wie in:

$('#btn').on("click", function() {
    alert("world");
});

Das Verhalten ist anders und erscheint seltsam.

1
gaetanoM

Sie rufen die Click-Funktion dreimal direkt auf (button.click ()), die unabhängig vom deaktivierten Attribut ausgelöst wird. 

Die deaktivierte Eigenschaft reagiert nur auf Klickereignisse. 

Siehe das aktualisierte Beispiel: 

    var button = $("#myButton");
var button2 = $("#myButton2");

button.prop("disabled", false);

button.on("click", function() {
    alert("world");
   button2.prop("disabled", false);
});

button2.prop("disabled", true); 

button2.on("click", function() {
    alert("world");
   button.prop("disabled", true);
});
<script src="https://code.jquery.com/jquery-1.12.2.min.js"></script>
<input type="button" id="myButton" value="button" onClick="alert('Hello')"/>
<input type="button" id="myButton2" value="button2" />

0
Aaron_Peazzoni

Die Verwendung von .prop () ist der richtige Weg. Ich denke, das Problem liegt in der Art und Weise, wie Sie es "testen". Sehen Sie sich dieses Beispiel an, in dem die Schaltflächen mit der Umschaltfläche korrekt deaktiviert/aktiviert werden, unabhängig davon, ob der Handler per Onclick oder mit Jquery verbunden ist.

window.testFunc = function(event) {
  if (!$('#myButton2').prop('disabled')) {
     alert("hello");
     console.log("hello");
  }
}

$(document).ready(function() {
  var button = $("#myButton2");

  button.on("click", function(event) {
    if (!$(this).prop('disabled')) {
        alert("world");    
        console.log("world");
    }
  });

  $('#toggleButton').click(function() {
	  $('#myButton1').prop('disabled', !$('#myButton1').prop('disabled'));
      $('#myButton2').prop('disabled', !$('#myButton2').prop('disabled'));
  });
  
  $('#tester').click(function() {
  	$('#myButton1').click();
    $('#myButton2').click();
    
  });

})
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<input type="button" id="myButton1" value="Vanilla button (hello)" onclick="window.testFunc(event)"/>
<input type="button" id="myButton2" value="jquery button (world)"/>
<input type="button" id="toggleButton" value="toggle disabled"/>
<input type="button" id="tester" value="test the buttons"/>

Die andere offensichtliche Lösung ist die Verwendung von Vanilla-Javascript. Nur weil Sie jQuery verwenden, bedeutet dies nicht, dass alles "gemacht" werden muss. Es gibt einige Dinge, die ohne jQuery ausreichen.

BEARBEITEN: Ich habe das Snippet bearbeitet, das zeigt, wie Sie verhindern können, dass Jquery mit .click () die Alarme auslöst.

0
mcgraphix