我想创建一个通过点击任意位置触发的一次性事件。单击按钮即可创建此事件。我不希望在点击按钮时触发事件,只有任何后续点击(包括按钮)。
所以说我有一些类似下面的HTML:
<body>
<div id="someparent">
<div id="btn"></div>
</div>
</body>
以下javascript(jquery):
$('#btn').click( function() {
$(document).one('click', function() {
console.log('triggered');
});
});
$('#someparent').click(function() {
// this must always be triggered
});
我想避免停止事件传播,但在上面的示例中,事件绑定到文档,然后事件冒泡,事件被触发。
解决此问题的一种方法似乎是将事件创建包装在超时中:
$('#btn').click( function() {
setTimeout(function() {
$(document).one('click', function() {
console.log('triggered');
});
}, 1);
});
$('#someparent').click(function() {
// this must always be triggered
});
现在,这很好用,但我想知道这是否安全。一些执行顺序的概念是否保证这一点总是有效,或者只是偶然的工作?我知道还有其他解决方案(例如另一个嵌套的.one()
事件),但我特意寻找setTimeout和事件传播如何互操作的答案。
以下小提琴显示两个div。第一个行为错误(文档事件立即触发)。单击第二个div,然后在文档(白色区域)上的任何位置说明所需行为:
答案 0 :(得分:8)
事件冒泡意味着,在事件触发最深可能元素后,它会以嵌套顺序触发父项。
来自:https://developer.mozilla.org/en-US/docs/Web/JavaScript/EventLoop#Adding_messages
添加消息
在Web浏览器中,只要事件发生,就会添加消息 是附加到它的事件监听器。如果没有听众,那么 事件丢失了。因此,单击具有单击事件处理程序的元素 将添加一条消息 - 与任何其他事件一样。
调用setTimeout将在时间之后向队列添加消息 作为第二个参数传递。如果队列中没有其他消息, 消息立即处理;但是,如果有消息, setTimeout消息必须等待其他消息 处理。因此,第二个参数表示最小值 时间而不是保证时间。
因此,您所拥有的行为不是偶然的,您可以保证在处理您在超时后添加的消息之前,处理队列中的消息。
答案 1 :(得分:2)
我对你想要的东西的理解:点击&#34;激活&#34;按钮,页面上任何位置的下一次单击(包括&#34;激活&#34;按钮)都应触发特殊事件。使用标志很容易处理:
var activationFlag = false;
$('#btn').click(function(event){
event.preventDefault();
if(!activationFlag) {
event.stopPropagation();
console.log('Global event activated');
}
activationFlag = true;
});
$('#someparent').click(function(event){
if(activationFlag) {
console.log('Time for a special event');
} else {
event.preventDefault();
event.stopPropagation();
}
});
答案 2 :(得分:2)
Here is a workaround使用标志而不是第二个事件:
var documentWaitingClick = false;
$(function() {
$(document).on('click', function(e) {
if (documentWaitingClick) {
//simulate the "one"
documentWaitingClick = false;
console.log('document click');
} else if (e.target.tagName === 'BUTTON') {
documentWaitingClick = true;
console.log('button click')
}
});
});