简体   繁体   English

点击被触发而没有预期的点击?

[英]Click being triggered without the expected click?

In short, I have addEventListener inside of addEventListener . 简而言之,我在addEventListener里面有addEventListener The event I'm listening to is click . 我正在听的事件是click Here's an example of my code: 这是我的代码示例:

function toggleElement() {
    // function stuff
}

anchor.addEventListener('click', (e) => {
    e.preventDefault();

    if (!anchorWrapper.classList.contains('active')) {
        // do some stuff
        window.addEventListener('click', toggleElement, false);
    } else {
        // do some stuff
        window.removeEventListener('click', toggleElement, false);
    }
});

Every time the anchor element is clicked, I assign an event listener to the window which listens to clicks. 每次单击锚元素时,我都会向监听点击的窗口分配一个事件监听器。 I'd expect the user to click the anchor, which in turn SHOULDN'T initialize toggleElement , but just assign a event listener to the window. 我希望用户单击锚点,而锚点又不应初始化toggleElement ,而只是将事件侦听器分配给窗口。 Then, according to my thinking (which turns out to be wrong), the function should only be initialized on the next, second click anywhere on the window. 然后,根据我的想法(事实证明是错误的),应仅在下次在窗口的任何位置第二次单击时才初始化该函数。 However, it get's run on the click on the anchor element. 但是,它是通过单击锚元素来运行的。

What am I not getting right? 我不对劲吗? How can I prevent the toggleElement function to not be initialized when a user clicks on the anchor element, but instead wait for click events on the window? 如何防止用户单击锚元素时不初始化toggleElement函数,而是等待窗口上的click事件?

The problem is that your first event is propagating through the DOM up to the node (in your case, window) that you have just added an event handler to. 问题在于,您的第一个事件是通过DOM 传播到您刚刚添加了事件处理程序的节点(在您的情况下是窗口)。 Because the propagation continues after your callback exits, which means after you have added the second event handler, it will hit the second event handler. 因为传播将在回调退出后继续进行,这意味着添加第二个事件处理程序后,它将触发第二个事件处理程序。

You can avoid this by using the stopPropagation method in your event. 您可以通过在stopPropagation中使用stopPropagation方法来避免这种情况。 You can also use some other technique such as a promise or a zero length timeout to relegate it to the next JS 'task' in the engine, but there are also reasons why you wouldn't want to do that. 您还可以使用其他技术(例如promise或零长度超时)将其重新分配给引擎中的下一个JS“任务”,但是还有一些您不想这样做的原因。

I have created some example code here, which also deals with the case where you want subsequent clicks inside the button (or whatever) to also trigger the second event handler. 我在这里创建了一些示例代码,它还处理了您希望按钮(或其他按钮)内的后续单击也触发第二个事件处理程序的情况。 Note also that I am having the second event handler unregister itself, which makes this logic slightly simpler. 还要注意,我正在让第二个事件处理程序注销自己,这使此逻辑稍微简单一些。

 let target = document.getElementById("target"); let targetWrapper = document.getElementById("targetWrapper"); function secondFunction() { console.log("Called second callback"); //alert("Second Function Called"); targetWrapper.removeEventListener('click', secondFunction, false); targetWrapper.classList.remove("active"); } target.addEventListener('click', (e) => { console.log("Called first callback") e.preventDefault(); if(!targetWrapper.classList.contains("active")){ targetWrapper.addEventListener('click', secondFunction, false); targetWrapper.classList.add("active"); e.stopPropagation(); } }); 
 body { font-size: 20px; font-family:sans-serif; } #targetWrapper { min-height: 400px; min-width: 400px; text-align: center; background-color: green; position:relative; } #target { vertical-align: middle; background-color:blue; color:red; padding:50px; position:absolute; top:100px; left:50px; } #targetWrapper.active{ outline: 3px solid red; } 
 <div id="targetWrapper"> <a id="target"> Click me! </a> </div> 

More info on event propagation and handlers: 有关事件传播和处理程序的更多信息:

DOM level 3 events DOM 3级事件

A question I answered earlier about order of event handling 我之前回答的有关事件处理顺序的问题

Example of event propagation 事件传播示例

Doesn't toggleElement get the "old" click event? toggleElement不会获得“旧”点击事件吗? Try putting it in a zero timeout: 尝试将其设置为零超时:

setTimeout(function() { window.addEventListener('click', toggleElement, false); });

Maybe the code is faster than your click? 也许代码比您的点击更快? I think when you click, the eventlistener is assigned but you are still 'clicking' so the second eventlistener detects the click as well. 我认为单击时会分配事件侦听器,但您仍在“单击”,因此第二个事件侦听器也会检测到该单击。 Correct me if I'm wrong. 如果我错了纠正我。

Try putting e.stopPropagation(); 尝试放置e.stopPropagation(); after e.preventDefault(); e.preventDefault(); .

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM