DOM事件和事件委托

DOM 事件模型及DOM 事件机制

通俗理解,事件是用户或者浏览器自己执行的某种动作,是文档或者浏览器发生的一些交互瞬间,比如点击(click)按钮等,这里的click就是事件的名称。JS与html之间的交互是通过事件实现的,DOM支持大量的事件。

事件流

规定的事件流有三个阶段: 事件捕获阶段,目标阶段,事件冒泡阶段。

image.png

示例:

 <div class="A">
    <div class="B">
      <div class="C">
        Click 
      </div>
    </div>
  </div>
复制代码

捕获

捕获是从A -> B -> C;看有没有函数监听
由网景公司提出的:事件有父元素传递到子元素的过程就叫捕获

冒泡

冒泡是从C -> B -> A;看有没有函数监听
由微软提出的:事件由子元素传递到父元素传递的过程,叫做冒泡

总结

由外向内找监听函数叫事件捕获;
由内向外找监听函数叫事件冒泡。

W3C标准

W3C标准:首先捕获,再冒泡
绑定在C的事件是按照代码的顺序发生的,其他非C元素则是通过冒泡或者捕获的触发。按照W3C的标准,先发生捕获事件,后发生冒泡事件。
所以事件的整体顺序是:
A元素捕获 -> B元素捕获 -> C元素代码顺序 -> B元素冒泡 -> A元素冒泡

事件绑定

API addEventListener

W3C: baba.addEventListener('click',fn,bool)

如果不传bool值 默认为false,冒泡

如果 bool 值为 true, 捕获

target 与 currentTarget 区别

e.target 用户操作的元素
e.currentTarget 程序员监听的元素

取消冒泡

捕获不能取消,冒泡可以 e.stopPropagation 中断冒泡

事件委托

原理:DOM元素的事件冒泡

事件委托是JavaScript中常用绑定事件的常用技巧,也叫事件代理(Event Delegation),顾名思义,“事件委托”是把原本需要绑定在子元素的响应事件(click、keydown…)委托给父元素,让父元素担当事件监听的职务。

事件委托的优点

<ul id="list">
    <li>click1</li>
    <li>click2</li>
    <li>click3</li>
    
    <!--   ...  -->
    
    <li>clickn</li>
</ul>
复制代码
  • 可以节省内存占用,减少事件注册(比如在ul上代理所有li的click事件)

如上面代码所示,如果给每个 <li> 列表项都绑定一个函数,那对内存的消耗是非常大的,因此较好的解决办法就是将<li>元素的点击事件绑定到它的父元素<ul>身上,执行事件的时候再去匹配判断目标元素。

  • 可以监听动态元素(监听目前不存在的元素的点击事件)

上述的例子中列表项<li>数量很少,我们给每个列表项都绑定了事件。

在很多时候,我们需要通过用户操作动态的增加或者删除列表项<li>元素,那么在每一次改变的时候都需要重新给新增的元素绑定事件,给即将删去的元素解绑事件。

如果用事件委托就没有这种麻烦,因为事件是绑定在父层,和目标元素的增减没有关系,执行到目标元素是在真正响应执行事件函数的过程中匹配的,所以使用事件在动态绑定事件的情况下可以减少很多重复性的工作。

示例:js.jirengu.com/lofareteni/…

setTimeout(()=>{
  const button = document.createElement('button')
  button.textContent='click1'
  div1.appendChild(button)
},1000)

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

封装事件委托

示例: js.jirengu.com/wapuposire/…

setTimeout(() => {
  const button = document.createElement('button')
  button.textContent = 'click1'
  div1.appendChild(button)
}, 1000)

on('click', '#div1', 'button', () => {
  console.log('button被点击了')
})

function on(eventType, element, selector, fn) {
  if (!(element instanceof Element)) {
    element = document.querySelector(element)
  }
  element.addEventListener(eventType, (e) => {
    const t = e.target
    if (t.matches(selector)) {
      //给元素添加一个监听,看当前的target是不是满足selector如果满足调用函数,不满足跳过
      fn(e)
    }
  })
}
复制代码
总结

事件委托就是把事件监听放在祖先元素(如父元素、爷爷元素)上。
好处是:1 节约监听数量 2 可以监听动态生成的元素。

引用了饥人谷教学图片,代码

© 版权声明
THE END
喜欢就支持一下吧
点赞0 分享