一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第3天,点击查看活动详情。
问题:假设有父子关系的两个div,子级div触发点击事件,然后删除父级元素节点,父级元素上的点击事件会被触发吗?
问题详情:
父级div的id为parent,子级div的id为son,父级div的点击事件监听函数为handleEmit,子级div的点击事件监听函数为handleRemove,handleRemove将移除id为parent的元素,而handleEmit会在控制台输出'emit'。请问当点击子级div时,handleEmit方法会打印'emit'吗?
可能的误区:
子级触发方法移除父级元素节点之后,父级元素节点已经从页面上消失,所以不会在触发父级上点击事件监听函数的方法
实际发生的事情:
子级触发点击事件方法之后,该方法移除父级节点,但是同时子级节点仍然在该父级容器中,所以事件冒泡依然会到父级节点上。
以下是示例代码:
<div id="removedNode">removed
<div id="emitNode">emit</div>
</div>
<script>
document.querySelector('#emitNode').addEventListener('click', emitRemove)
document.querySelector('#removedNode').addEventListener('click', handleRemoveEvent)
function emitRemove(){
console.log('emitRemove')
const node = document.querySelector('#removedNode')
document.querySelector('body').removeChild(node)
}
function handleRemoveEvent(){
console.log('handle')
}
</script>
输出结果将是:
emitRemove
handle
而如果你希望将节点移除之后,父级元素parent上的点击事件监听函数不再触发,那么你要在emitRemove方法体内将parent上的事件监听函数移除掉,也就是说:
function emitRemove(){
console.log('emitRemove')
const node = document.querySelector('#removedNode')
node.removeEventListener('click',handleRemoveEvent) //新增
document.querySelector('body').removeChild(node)
}
新增移除事件监听函数的代码,并执行这个函数之后,父级元素上的点击事件监听函数将不会再触发。 现在的输出结果:
emitRemove
总结,以及最后的tip
尽管很难去想象到这个事,但是你要知道移除了父节点之后,只是DOM文档上没有了该节点,但是依然会执行父节点上的方法。接下来还有另一个demo可以让我们观察到这个现象。 示例代码如下:
<div id="removedNode">removed
<div id="emitNode">emit</div>
</div>
<script>
let emitNode = document.querySelector('#emitNode')
let removedNode = document.querySelector('#removedNode')
emitNode.addEventListener('click', emitRemove)
removedNode.addEventListener('click', handleRemoveEvent)
function emitRemove(){
console.log('emitRemove')
// removedNode.removeEventListener('click',handleRemoveEvent)
if(!document.querySelector('body').contains(removedNode)){
return
}
document.querySelector('body').removeChild(removedNode)
}
function handleRemoveEvent(){
console.log('handle')
}
</script>
当你在控制台点击emit时,会触发emitRemove方法移除父节点,并且打印后续的handle。但是如果你在控制台继续执行emitNode.click(),尽管此时页面上已经没有了这两个div,但是id为removedNode的节点上的事件监听函数依然会被触发。也就是说,控制台会打印:
emitRemove
handle