避免重复addEventListener的核心就是在添加前通过removeEventListener将已经添加的处理函数进行移除
。如下代码为id=btn
的元素添加click
事件的处理函数clickHandler
:
const $btn = document.getElementById('btn');
function clickHandler() {
console.info(`this is in clickHandler`);
}
$btn.removeEventListener('click', clickHandler);
$btn.addEventListener('click', clickHandler);
但是在这里涉及到一个问题,JavaScript中函数是引用类型,因此在进行removeEventListener
时,第二个参数需要和addEventListener
时的引用相同,否则无法达到移除的效果。如下代码所示:
Html部分代码如下
<body>
<h1 id="btn">click here</h1>
<section>
<button onclick="addListener()" id="btnForBtn">add handler for click here</button>
</section>
JavaScript代码如下
const $btn = document.getElementById('btn');
let count = 0;
function addListener() {
function clickHandler() {
console.info(`this is in clickHandler but created ${++count} times`);
}
$btn.removeEventListener('click', clickHandler);
$btn.addEventListener('click', clickHandler);
}
效果图,如下:
点击add handler to click here
按钮为click here
按钮添加点击事件,并在添加前进行移除,希望达到唯一处理函数的效果。右侧输出展示的是六次add handler to click here
按钮点击,一次click here
按钮点击的效果。可以看到,并未达到预期。原因是:每次执行函数addListener都重新创建了clickHandler函数,因此在进行removeEventListener时并未将原有的处理函数进行移除
。
如果将clickHandler
移动到addListener
函数之外仅进行一次定义,那么是可以达到唯一添加的效果,但是在有些业务需求中需要进行如此类代码结构的编写方式(如Vue中,在directive的各生命周期中进行事件绑定)。而此时为了达到唯一绑定的效果,其实就是保存clickHandler的唯一引用的问题。如果不能提取到外部作为全局变量,那么换个思路,作为待绑定元素的属性也就可以了,JavaScript代码如下:
const $btn = document.getElementById('btn');
let count = 0;
function addListener() {
if ($btn.clickHandler) {
$btn.removeEventListener('click', $btn.clickHandler);
}
$btn.clickHandler = () => {
console.info(`this is in clickHandler but created ${++count} times`);
};
$btn.addEventListener('click', $btn.clickHandler);
}
效果图,如下:
这里需要注意的是:
- 过多的在元素上绑定属性,有可能会造成性能的损耗和增加维护的成本
clickHandler
属性的定义应该进行命名空间的限制,以避免发生同名属性覆盖的问题
最后需要提到的是,对同一个元素的同一个事件重复进行处理函数的添加,是只生效一次的,如下代码中:
const $btn = document.getElementById('btn');
const clickHandler = () => {
console.info('this is handler1')
};
// 多次添加同一个事件处理函数,则不会重复执行
$btn.addEventListener('click', clickHandler);
$btn.addEventListener('click', clickHandler);
在页面中对$btn
元素进行点击,clickHandler
将只执行一次。
学艺不足,欢迎各位看官纠正指错,祝各位生活愉快,工作顺利~~