zoukankan      html  css  js  c++  java
  • 如何避免重复addEventListener?

    避免重复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将只执行一次。

    ==================

    实战:plus会员中战略banner解决绑定多个addEventListener,把原来绑定到函数上改为绑定到属性上

    bindEvents() {
        const activity = this.isNewFormalSub ? document.getElementById('activitySub') : document.getElementById('activity');
        if (activity) {
            [].forEach.call(activity.querySelectorAll('.swiper-slide'), item => {
                if (item.clickHandler) {
                    item.removeEventListener('click', item.clickHandler);
                }
                item.clickHandler = () => {
                    console.log('触发点击');
                    const ins = item.getAttribute('data-ins');
                    this.openLink(this.bannerData[ins], parseInt(ins));
                };
                item.addEventListener('click', item.clickHandler);
            });
        }
    }
    
  • 相关阅读:
    [nodejs] 静态资源服务器
    [nodejs]fs 读数据流和写数据流
    [nodejs]fs文件模块-练习
    [nodejs] fs文件模块
    利用SqlServer触发器自动更新表updatetime字段值
    python发送邮件至多人
    mybatis-plus获取Timestamp类型,无法获取变量null
    1.iOS第一个简单APP
    Mysql浅析
    Nginx编译安装Lua模块
  • 原文地址:https://www.cnblogs.com/xiaozhumaopao/p/14336825.html
Copyright © 2011-2022 走看看