Vanilla JavaScript
在vanilla JavaScript中,可以使用以下语句轻松启用和禁用按钮:
button.disabled = state;
这在人类尝试单击按钮和以编程方式单击按钮时都有效:
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')"/>
这在使用MouseEvent
界面时也有效:
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
不过,我似乎无法对jQuery做同样的事情:
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')"/>
button.prop("disabled", true);
和 button.attr("disabled", true);
都只是更改按钮元素的 disabled
属性,但都不会禁用实际的单击事件。这意味着只要调用button.click();
,就会触发事件,即使按钮被禁用也是如此!
此外,"world"和"Hello"以错误的顺序输出。
我能想出的最简单的代码来模拟原版JavaScript版本的行为,是这样的:
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')"/>
当然,这是荒谬的复杂和"黑客"代码来实现像禁用按钮这样简单的事情。
<小时 />我的问题
- 为什么jQuery与vanilla JS不同,在禁用按钮时不会禁用事件?
- 这是否被视为jQuery中的错误或功能?
- 我忽略了什么吗?
- 有没有更简单的方法可以在jQuery中获取预期的行为?
为了达到预期的结果,你可以利用 jQuery 触发click
处理程序中的.isTrigger
来确定事件是否由 javascript
触发,而不是用户操作。
将属性事件侦听器定义为命名函数,其中可以传递this
以在if
条件下检查disabled
属性是否调用alert()
或未调用。
使用 .attr("disabled", "disabled")
在元素处设置disabled
,.removeAttr("disabled")
删除属性; .attr("onclick", null)
删除处理程序onclick
事件属性; .attr("onclick", "handleClick(true)")
重置事件属性。
<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>
如果你看看jquery-1.12.4.js在以下几行:
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" ) ) {
您将看到根据委派类型对事件的不同处理:
$(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>
当然,如果您附加事件,例如:
$('#btn').on("click", function() {
alert("world");
});
行为不同,看起来很奇怪。
使用 .prop(( 是正确的方法。我认为问题在于您"测试"它的方式。请参阅此示例,其中使用切换按钮正确禁用/启用按钮,无论处理程序是通过 onclick 还是使用 jquery 附加的。
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"/>
另一个明显的解决方案是只使用vanilla javascript。仅仅因为你正在使用jQuery并不意味着所有事情"必须"使用它来完成。有些事情可以在没有jQuery的情况下完成。
编辑:我编辑了显示如何防止jquery的.click((实际触发警报的代码片段。
你直接调用点击函数 3 次 ( button.click(( (,无论禁用的属性如何,它都会触发。
禁用的属性仅响应单击事件。
请参阅更新的示例:
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" />