为何设置details的open属性后添加toggle监听器仍触发回调?
为什么设置details的open属性后添加toggle监听器仍会触发回调?
你的代码如下:
const $details = document.querySelector('.my-details') const onDetailsToggle = () => { console.log('details toggled!') } const foo = () => { $details.open = true $details.addEventListener('toggle', onDetailsToggle, { once: true }) } foo()
核心原因在于浏览器处理details元素open属性变更的异步逻辑:
- 当你同步设置
$details.open = true时,浏览器不会立即触发toggle事件,而是将事件触发的任务放入微任务队列。 - 添加事件监听器的操作是同步执行的,会在微任务队列里的事件触发前完成。
- 等所有同步代码执行完毕后,微任务开始处理,此时
toggle事件触发,对应的监听器已经存在,所以onDetailsToggle回调会被执行。
你可以做个验证:把添加监听器的操作放进setTimeout(宏任务)里,此时回调就不会执行了——因为宏任务的执行时机在微任务之后,toggle事件已经触发过了:
const foo = () => { $details.open = true setTimeout(() => { $details.addEventListener('toggle', onDetailsToggle, { once: true }) }, 0) } foo()
内容的提问来源于stack exchange,提问作者Aaron Parisi
相关产品推荐
相关产品推荐

