也许我们应该从澄清一些事情开始。
浏览器中的事件,更像是一个“嵌套层次结构”,然后是一个队列——它的工作原理被称为事件冒泡——[维基百科][1]
但是,本质上,当添加一个 EventListener 时,您正在做的事情是连接到 DOM 的一个或多个点,然后说,嘿,当 X 事件通过这里时,使用函数 Y 来处理它,然后再将它沿堆栈传递。
一旦“添加”了一个 EventListener,它就会保持活动状态,等待给定一个事件。它究竟做了什么在它的处理函数中定义。
let myYFunction = function( e ) { ... }
let myXListener = baton.addEventListern('X event', myYFunction );
// at this point, anytime 'X event' happens to baton, myYFunction will
// be called to handle it...
现在让我们看看你的例子,让我们把事情分解一下,
const baton = document.querySelector('button');
第一行是简单地查询 DOM,以在页面中查找类型为“按钮”的第一个元素。对...这是我们要插入事件处理程序的“位置”。我们可以将它们添加到任何元素,在 DOM 中的任何位置,如果我们愿意,我们甚至可以挂钩到“body”元素。
好的,那么你有这个,
baton.addEventListener('mousedown', (e) => {
console.log('baton');
baton.addEventListener('click', (e) => {
console.log('baton click');
});
});
这是“嵌套”“click”事件侦听器的创建,但只有在“mousedown”事件被“处理”之后。没有真正的理由必须在 mousedown 处理程序的函数体中注册“click”事件。
如果我们稍微重写一下,可能会更清楚实际发生了什么。
baton.addEventListener('mousedown', (e) => {
console.log('baton mousedown');
}
baton.addEventListener('click', (e) => {
console.log('baton click');
});
此外,我还要指出,目前它是如何“工作”的——但它实际上隐藏了一点草率的编码......你每次触发“mousedown”事件时都会看到一个新的“click”事件监听器正在注册...所以最终您可能会得到很多很多点击处理程序来响应单个“点击”事件...查看 MDN 以了解有关 [this][2] 的更多信息
我希望这能回答你最初关于发生了什么的问题。
对于您的问题“当我单击一个按钮时,我将 '指挥棒' 和 '指挥棒点击' 记录到控制台。现在我的问题是这里到底发生了什么?” ——对我来说,它看起来像这样:
- 添加了“mousedown”事件监听器,但没有“执行”
- 'mousedown' 事件发生了,现在你的 'mousedown' 监听器执行它的函数,该函数又注销到控制台,并注册一个新的 'click' 处理程序——但同样,不执行。
继续前进,对于指挥棒看到的每个“鼠标按下”,都会重复第 1 步和第 2 步。此外,对于通过接力棒传递的任何“点击”事件——在接力棒上的每次“鼠标按下”之后都会发生:
- 发生“点击”事件,然后执行“点击”处理程序并注销到控制台。
SPA 事件处理策略
使用 SPA 时,显示多个“页面”,在同一个页面加载中......它可能会变得混乱,所有这些事件侦听器都在相互堆积。如果您打算在 SPA 的“页面”之间使用 eventListeners,您可能还想研究如何“删除”它们。- [MDN][3]
这样,您的 SPA 的当前“页面”只有活动监听器。
此外,考虑“概括”您的处理程序,并将它们附加到 DOM 中更高的位置......这将允许您只有少数事件侦听器将事件“路由”到它们的“逻辑”处理程序。
随机/不同的行为
通过上面概述的步骤,1、2 和 3 以及它们如何不会同时发生。您将看到似乎是随机输出到控制台的内容......尝试运行类似这样的东西,以获得正确的感觉:
let cCount = 0;
let mCount = 0;
let tCount = 0;
const baton = document.querySelector('button');
baton.addEventListener('mousedown', (e) => {
console.log('mousedown # ' + (mCount++) + ' order:' + tCount++);
baton.addEventListener('click', (e) => {
console.log('click # ' + (cCount++) + ' order:' + tCount++);
});
});
[1]: https://en.wikipedia.org/wiki/Event_bubbling#:~:text=Event%20bubbling%20is%20a%20type,Provided%20the%20handler%20is%20initialized )。[2]:https ://developer.mozilla.org/en-US/docs/Web/API/EventTarget/addEventListener
[3]:https ://developer.mozilla.org/en-US/docs/Web/API /EventTarget/removeEventListener