js基础:addEventListener与removeEventListener使用时,涉及的问题(包括事件捕获、冒泡,removeEventListener不生效问题)

目录

第一章 理解addEventListener与removeEventListener

1.1 addEventListener的理解

1.1.1 语法

1.1.2 参数解释 

1.1.3 使用方法

1.2 removeEventListener的理解

1.2.1 语法

1.2.2 使用说明

第二章 事件捕获与事件冒泡

2.1 理解事件捕获

2.2 理解事件冒泡

2.3 解决事件冒泡的两种方法

2.3.1 方法一:阻止事件冒泡

2.3.2 方法二:事件委托

第三章 解决addEventListener多次触发,removeEventListener不生效问题

2.1 项目bug

2.2 处理过程

2.3 最终处理

2.4 总结


第一章 理解addEventListener与removeEventListener

1.1 addEventListener的理解

1.1.1 语法

element.addEventListener(event, function, boolean)

1.1.2 参数解释 

  • element获取的标签元素
  • event指定事件名(注意不需要使用on,例如,使用 "click" ,而不是使用 "onclick")

     -- 常见的事件名

  1. click 单击鼠标左键触发
  2. dblclick 双击鼠标左键触发
  3. mousedown 单击任意一个鼠标按钮时触发
  4. mouseup 松开任意一个鼠标按钮时触发
  5. mousemove 鼠标在某个元素上移动时触发
  6. mouseenter 鼠标移入标签时触发 
  7. mouseleave 鼠标移入标签是触发

        ……

  • function指定要事件触发时执行的函数(注意:默认事件对象event会作为第一个参数传入函数)
  • boolean指定是事件捕获还是事件冒泡(默认为false,false --> 事件冒泡,true--> 事件捕获

1.1.3 使用方法

  • (注意:小编用的项目里的代码做的demo,为大家提供思路)
const bookListFileUplodDom = this.$refs[`upload-book-list-file-${id}`] // 这里是获取dom标签
bookListFileUplodDom.addEventListener('change', function (e) { // 添加监听事件
    connsole.log(e)
}, false)

HTML DOM addEventListener() 方法 | 菜鸟教程

1.2 removeEventListener的理解

1.2.1 语法

element.removeEventListener(event, function, boolean)

1.2.2 使用说明

const bookListFileUplodDom = this.$refs[`upload-book-list-file-${id}`] // 这里是获取dom标签
bookListFileUplodDom.removeEventListener('change', function (e) { // 移除监听事件
    connsole.log(e)
}, false)

第二章 事件捕获与事件冒泡

2.1 理解事件捕获

  • 顾名思义:捕获—— 一个刑事案件,警察首先从表面的线索开始,然后一点一点的到向更深层次的去了解罪案人,最终抓到作案人,这个过程就是捕获。那好,事件捕获的原理类比的看,dom事件由外向里逐级传递的过程
    <div class="father" style="width: 200px;height: 100px;background-color: red;margin: auto;">
        father
        <div class="son" style="width: 100px;height: 50px;background-color: skyblue;">
            son
        </div>
    </div>

    <script>
        /*
            事件捕获
        */
        const son = document.querySelector('.son');
        // 给son注册单击事件
        son.addEventListener('click', function (event) {
            alert('son');
        }, true);
        // 给father注册单击事件
        const father = document.querySelector('.father');
        father.addEventListener('click', function (event) {
            alert('father');
        }, true);
        // 给document注册单击事件,省略第3个参数
        document.addEventListener('click', function () {
           alert('document');
        }, true)
    </script>
  • 展示效果: 通过点击最里层的son标签,会从最外层的dom逐层遍历进去

  •  实现顺序: document -> html ->body ->father ->son

2.2 理解事件冒泡

  • 顾名思义:冒泡—— 一桶水,让我们烧开时,会有泡泡从桶的底部慢慢的浮向表面,这个过程就是冒泡。那好,事件冒泡的原理也是如此,dom事件由里向外逐级传递的过程
  • 例子:
    <div class="father" style="width: 200px;height: 100px;background-color: red;margin: auto;">
        father
        <div class="son" style="width: 100px;height: 50px;background-color: skyblue;">
            son
        </div>
    </div>

    <script>
        /*
         冒泡阶段 如果addEventListener 第三个参数是 false 或者 省略 
        如果参数为true,则为捕获阶段
        */
        const son = document.querySelector('.son');
        // 给son注册单击事件
        son.addEventListener('click', function (event) {
            alert('son');
        }, false);
        // 给father注册单击事件
        const father = document.querySelector('.father');
        father.addEventListener('click', function (event) {
            alert('father');
        }, false);
        // 给document注册单击事件,省略第3个参数
        document.addEventListener('click', function () {
           alert('document');
        })
    </script>
  • 展示效果: 通过点击最里层的son标签,会从最里层的son标签逐层遍历出来

  • 实现顺序:son -> father ->body -> html -> document,逐层传递

2.3 解决事件冒泡的两种方法

2.3.1 方法一:阻止事件冒泡

  • event.stopPropagation()
    <div class="father" style="width: 200px;height: 100px;background-color: red;margin: auto;">
        father
        <div class="son" style="width: 100px;height: 50px;background-color: skyblue;">
            son
        </div>
    </div>

    <script>
        const son = document.querySelector('.son');
        // 给son注册单击事件
        son.addEventListener('click', function (event) {
            // 添加阻止事件冒泡
            event.stopPropagation()
            alert('son');
        }, false);
        // 给father注册单击事件
        const father = document.querySelector('.father');
        father.addEventListener('click', function (event) {
            alert('father');
        }, false);
        // 给document注册单击事件,省略第3个参数
        document.addEventListener('click', function () {
           alert('document');
        })
    </script>
  • 效果展示

  •  描述,在son标签配置阻止冒泡事件之后,我们点击son标签,就不会再出现会逐层执行点击事件冒泡效果了

2.3.2 方法二:事件委托

  • 什么是事件委托:对“事件处理程序过多”问题的解决方案就是事件委托。事件委托利用了冒泡,只指定一个事件处理程序,就可以管理某一类型的所有事件。(比如父标签与子标签都要执行相同的代码,这个时候我们只需要在父标签上绑定一个方法就好了,不需要在子标签上也绑定一个相同的方法
    <div class="father" style="width: 200px;height: 100px;background-color: red;margin: auto;">
        father
        <div class="son" style="width: 100px;height: 50px;background-color: skyblue;">
            son
        </div>
    </div>

    <script>
        // 给father注册单击事件
        const father = document.querySelector('.father');
        father.addEventListener('click', function (event) {
            event.stopPropagation();
            alert('son/father');
        }, false);
        // 给document注册单击事件,省略第3个参数
        document.addEventListener('click', function () {
           alert('document');
        })
    </script>
  • 效果展示:

  • 描述:不管是点击son标签还是点击father标签,他们执行的方法都是相同的

第三章 解决addEventListener多次触发,removeEventListener不生效问题

3.1 项目bug

  • 项目情况:有地方触发多次执行添加监听的代码,我需要做的是每次添加监听在完成逻辑之后马上移除对应的监听,从而防止调查一次函数时,多个监听执行逻辑
  • bug效果图

  • 描述:小编每次点击导入,会添加一个监听事件, 当用户点击打开上传文件成功,数据变化,执行代码逻辑,但是当小编在不停的取消导入或者多次导入的时候,我们可以发现在数据发生变化的时候我们点击了多少次,就执行多少次逻辑,说明只是添加addEventListener监听事件,并没有及时removeEventListener移除对应的监听事件,而且小编踩过的坑:设置了移除监听事件removeEventListener,依然还是这种效果的情况,以下就是小编的具体实现方法:

3.2 处理过程

  • 第一次尝试:
const bookListFileUplodDom = this.$refs[`upload-book-list-file-${id}`] // 这里是获取dom标签

// 配置效果无效
bookListFileUplodDom.addEventListener('change', function (e) { // 移除监听事件
    connsole.log(e)
}, false)

bookListFileUplodDom.removeEventListener('change', function (e) { // 移除监听事件
    connsole.log(e)
}, false)

结果:这种方法监听的事件看起来和移除的事件是一样的,但其实这两个方法并不相同,这就涉及到数据类型、堆与栈的知识了(小编说明一下:函数是引用数据类型,在js中也算是特殊的对象,它会被存储在堆中,而这种方法相当于在堆中开了两个内存分别存储这两个对象,从而导致他们不是同一事件,最终导致移除监听事件没有效果),他们的内存是不共用的,这点在使用时一定要注意,这次尝试也让我们知道了,要将两者搭配使用,首先要确保添加与移除引用的是同一内存里的监听函数

  • 第二次尝试:
const bookListFileUplodDom = this.$refs[`upload-book-list-file-${id}`] // 这里是获取dom标签

function handler (e) { // 移除监听事件
    connsole.log(e)
}

// 配置有效果(但是不能满足小编每次执行完成就移除的需求)
bookListFileUplodDom.addEventListener('change', handler, false)

bookListFileUplodDom.removeEventListener('change', handler, false)

结果:这种处理是先addEventListener再removeEventListener是可以把刚刚add的remove掉的,但是他不符合小编的要求,小编需要把上一次add的remove掉,再重新add,这样就不会触发多次执行。问题就在这:再执行一次时,这个方法也重新声明了,上一次add的function和这次remove的不是同一个function,他们的内存不同,所以小编又重新调整了下代码:

3.3 最终处理

<script>

let bookListHandler = null // 定义一个自变量的保存上一次的监听函数(移除监听函数使用)

export default {

  methods: {
    toImportBookList (id) {
      const bookListFileUplodDom = this.$refs[`upload-book-list-file-${id}`]
      bookListFileUplodDom.removeEventListener('change', bookListHandler, false) // 每次调用函数执行移除上一次的添加的监听
      bookListFileUplodDom.click()
    },
    importBookList (id) {
      const _this = this
      const bookListFileUplodDom = this.$refs[`upload-book-list-file-${id}`]
      bookListHandler = function (e) { // 将执行的监听函数赋值
        console.log(e)
      }
      bookListFileUplodDom.addEventListener('change', bookListHandler, false) // 添加监听事件
    },
  }
}
</script>
  • bug得到解决,成功!

3.4 总结

最后,说了这么多,特别重要的是要知道,addEventListener和removeEventListener使用时操作的一定要是同一个function(同一内存) 还需要知道的知识有JavaScript的数据类型、堆、栈,最后也能了解到深浅克隆了。

  • 29
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
JavaScript中,addEventListener()和removeEventListener()是用于处理事件的两个方法。 addEventListener()方法用于向指定的元素添加事件监听器。它接受三个参数:事件类型、处理函数和一个可选的布尔值参数。事件类型是一个字符串,表示要监听的事件类型,比如"click"、"keydown"等。处理函数是一个回调函数,当事件被触发,会执行这个函数。可选的布尔值参数表示事件是否在捕获阶段触发,默认为false,表示在冒泡阶段触发。该方法可以多次调用,以添加多个事件监听器。 removeEventListener()方法用于从指定的元素中移除事件监听器。它接受相同的三个参数:事件类型、处理函数和可选的布尔值参数。要移除监听器,必须使用与添加监听器相同的参数。如果事件类型、处理函数或者布尔值参数不匹配,那么移除操作将无效。该方法可以用来取消之前通过addEventListener()添加的事件监听器。 这两个方法的使用可以帮助我们管理事件,实现更灵活的交互。通过addEventListener()可以在元素上添加多个监听器,处理不同的事件类型,以及在不同的阶段触发。而removeEventListener()可以在不需要监听某个事件,通过传入相同的参数来移除已添加的监听器,以避免浪费资源或者避免不必要的事件处理。总的来说,这两个方法是JavaScript中处理事件的常用工具,可以帮助我们实现更好的用户体验。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值