真的会用addEventListener吗,别掉到坑里了
真的会用addEventListener吗,别掉到坑里了
大家用addEventListener
肯定也听过removeAddeventListener
,但是不少朋友使用有误区。
事件的添加和移除
// 示例1
// 添加事件
document.addEventListener('click', (e) => {
console.log('冒泡 点击', e)
});
// 移除事件
document.removeEventListener('click', (e) => {
console.log('冒泡 点击', e)
});
上面的添加没有问题,但是移除没有效果了,就算移除的方法的代码跟添加一模一样也不行。
因为在使用removeEventListener
的时候,要确保回调函数时同一个
// 示例2
function fn(e) {
console.log('冒泡 点击', e)
}
// 添加事件
document.addEventListener('click', fn);
// 移除事件
document.removeEventListener('click', fn);
向上面的方式使用就没有问题了。
但是我们经常在使用框架(以vue为例)的时候,有意无意的又会放上面示例1的错误了,我就经常看到这样的错误。
// 示例2
methods: {
fn(e) {
console.log('冒泡 点击', e);
this.abcFn();
},
abcFn() {
this.abc =[Date.now()];
},
}
mounted() {
// 添加事件
document.addEventListener('click', this.fn.bind(this));
// 移除事件
document.removeEventListener('click', this.fn.bind(this));
}
这样写的童鞋主要是因为在fn
方法在还要调用abcFn
方法,怕this
不对,所以想着bind
以下,但是这样其实犯了跟示例1一样的问题,因为每次bind
都会返回一个新方法的。
事件的冒泡与捕获
addEventListener
其实是有三个参数的,就是是否使用事件捕获,默认是false
,也就是默认用的是事件冒泡,这也是现在主流的方式。
// 示例4
<template>
<section>
<div id='abc' ref='abc'>
abc
</div>
<section>
<div id='efg' ref=efg>
efg
{{abc}}
</div>
</section>
</section>
</template>
this.$refs.abc.addEventListener('click', (e) => {
console.log('abc 冒泡 点击', e);
});
this.$refs.efg.addEventListener('click', (e) => {
console.log('efg 捕获 点击', e);
}, true);
document.addEventListener('click', (e) => {
console.log('document 冒泡 点击', e);
})
1.如果我们在id为abc的div内点击,我们会看到打印两个冒泡
2.如果在id为efg内点击,会先打印一个捕获,打印一次冒泡。
3.如果我们在id为abc和id为efg的div外点击,只会打印一次冒泡
这三种情况应该不难理解,觉得不好理解的话,建议静下心来了解下时间的捕获和冒泡过程。
使用stopPropagation
我们有时需要阻止冒泡。 1.我们在abc里面点击的时候,不希望触发外层的 document的点击回调
this.$refs.abc.addEventListener('click', (e) => {
console.log('abc 冒泡 点击', e);
e.stopPropagation();
});
2.我们在efg里面点击的时候,不希望触发外层的 document的点击回调
this.$refs.efg.addEventListener('click', (e) => {
console.log('efg 捕获 点击', e);
e.stopPropagation();
}, false);
这里的一样跟我们的预期是一致的。
3.但是我们如果把上面绑在efg的事件捕获,改成绑在document上面呢
document.addEventListener('click', (e) => {
console.log('efg 捕获 点击', e);
e.stopPropagation();
}, false);
为什么这样说呢?因为一般使用过程中大家都习惯使用事件冒泡,但是有的第三方库偶尔会使用事件捕获,这时要注意了,因为现在一般都会把事件绑定到document
上,如果在事件使用了阻止冒泡会怎样?
现在之后打印捕获了,即使在id为efg的div里面点击也是如此。也就是说,你在时间冒泡里面的写回调方法都没有执行了,是不是很坑。
总结
- 慎用时间捕获,尤其是在外层,比如document里面使用,
- 慎用阻止冒泡
- 分类:
- Web前端