DOM事件与事件委托

95 阅读3分钟

一、DOM事件机制

从外向内找监听函数,叫事件捕获

从内向外找监听函数,叫事件冒泡

image.png

  • W#C事件模型:默认先捕获,再冒泡。

addEventListener

  1. 事件绑定 API
  • IE 5*:baba.attachEvent('onclick', fn) // 冒泡
  • 网景:baba.addEventListener('click',fn) // 捕获
  • W3C:baba.addEventListener('click', fn, bool)
  1. 如果 bool 不传或为 falsy
  • 就让 fn 走冒泡,即当浏览器在冒泡阶段发现 baba 有 fn 监听函数,就会调用 fn,并提供事件信息
  1. 如果 bool 为 true
  • 就让 fn 走捕获,即当浏览器在捕获阶段发现 baba 有 fn 监听函数,就会调用 fn ,并提供事件信息

target v.s. currentTarget

  1. 区别
  • e.target - 用户操作的元素
  • e.currentTarget - 程序员监听的元素
  • thise.currentTarget,不推荐使用
  1. 举例
  • div > span{文字},用户点击文字
  • e.target 就是 span
  • e.currentTarget 就是 div

取消冒泡

  1. 捕获不可取消,但冒泡可以
  • e.stopPropagation() 可中断冒泡,浏览器不再向上走
  • 一般用于封装某些独立的组件

不可阻止默认动作

  1. scroll 事件不可阻止默认动作
  • MDN 搜索 scroll event,看到 Bubbles 和 Cancelable
  • Bubbles 的意思是该事件是否冒泡,所有冒泡都可取消
  • Cancelable 的意思是开发者是否可以阻止默认事件
  • Cancelable 与冒泡无关
  • 推荐看 MDN 英文版,中文版内容不全 image.png

如何阻止滚动

  1. 有些事件不可阻止默认动作
  • 阻止 scroll 默认动作没用,因先有滚动才有滚动事件
  • 要阻止滚动,可阻止 wheel 和 touchstart 的默认动作
  • 注意你需要找准滚动条所在的元素
  • 但是滚动条还能用,可用 CSS 让滚动条 width: 0
  1. CSS 也行
  • 使用 overflow: hidden 可以直接取消滚动条
  • 但此时 JS 依然可以修改 scrollTop

二、自定义事件

  1. 浏览器自带事件,一共100多种事件,列表在 (事件参考 | MDN (mozilla.org)
  2. 开发者能不能在自带事件之外,自定义一个事件?可以

三、事件委托

  1. 对"事件处理程序过多"问题的解决方案,就是需要触发子事件时,只用给某父元素或祖先元素指定一个事件处理程序,就可以管理某一类型的所有事件.事件委托原理原理就是事件冒泡原理.
  2. 场景一
  • 给 100 个按钮添加点击事件
  • 答:监听这 100 个按钮的祖先元素,等冒泡的时候判断 target 是不是这 100 个按钮中的一个
js代码
div1.addEventListener('click', (e)=>{
    const t = e.target
    if(t.tagName.toLowerCase() === 'button'){
        console.log('button'被点击了)
        console.log('button'内容是 + t.textContext) // 获取被点击元素的文本内容
        console.log('button 的data-id是:'+ t.dataset.id) // 获取被点击元素的dataset.id
    }
})
  1. 场景二
  • 监听目前不存在的元素的点击事件
  • 答:监听祖先元素,等点击的时候看看是不是我想要监听的元素即可
js代码
setTimeout(()=>{
    const button = document.createElement('button')
    button.textContent= 'click 1'
    div1.appendChild(button)
},1000)

div1.addEventListener('click', (e)=>{
    const t = e.target
    if(t.tagName.toLowerCase() === 'button'){
        console.log('button 被 click')
    }
})

4.事件委托优点:

  • 省监听数(内存)
  • 可以监听动态元素

四、封装事件委托

  1. 要求写出这样一个函数 on('click', '#testDiv', 'li', fn)
  • 当用户点击#testDiv里的li元素时,调用 fn 函数
  • 要求用到事件委托
  1. 答案一
  • 判断 target 是否匹配 'li'
  1. 答案二
  • 递归判断 target / target的爸爸 / target的爷爷