DOM事件机制和事件委托

286 阅读2分钟

事件机制

事件捕获和事件冒泡

  • 事件捕获:网景的事件流叫做事件捕获,从外向内,找监听函数
  • 事件冒泡:IE的事件流叫做事件冒泡,从内向外,找监听函数 捕获机制示意图 DOM1.png

事件绑定API

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

取消冒泡

捕获不可取消,但是冒泡可取消

e.stopPropagation()可中断冒泡,浏览器不在向上走;

不可阻止默认动作

  1. 有些事件不能阻止默认动作
  • MDN搜索scroll event,看到Bubbles和 Cancelable
  • Bubbles的意思是该事件是否冒泡,所有冒泡都可取消
  • Cancelable的意思是开发者是否可以阻止默认事件
  • Cancelable与冒泡无关
  • 推荐看MDN英文版,中文版内容不全
  1. 如何阻止滚动 scroll 事件不可阻止默认动作
  • 阻止scroll默认动作没用,因先有滚动才有滚动事件
  • 要阻止滚动,可阻止 wheel和 touchstart的默认动作
  • 注意你需要找准滚动条所在的元素,示例
  • 但是滚动条还能用,可用CSS让滚动条width: 0 (::-webkit-scrollbar { width: 0 !important })
  1. CSS也行    使用overflow: hidden可以直接取消滚动条

事件委托

事件委托就是利用事件冒泡,只指定一个事件处理程序,就可以管理某一类型的所有事件。

事件委托:不监听元素自身,而是监听其祖先元素,然后判断e.target是不是该元素(或该元素的子元素)

优点:

  1. 省监听数,减少内存消耗
<div id="div1">
  <button>click 1</button>
  <button>click 2</button>
  <button>click 3</button>
  <button>click 4</button>
  <button>click 5</button>
</div>

<script>
 div1.addEventListener('click',(e)=>{
    //用t保存目标元素,否则e会消失
    const t = e.target
    if(t.tagName.toLowerCase() === 'button'){
         console.log('button内容是:' + t.textContent)
    }
})
</script>
  1. 可以监听动态元素(暂时不存在的元素)
<div id="div1">
</div>

<script>
setTimeout(()=>{
  //div1里面添加一个button
  const button = document.creatElement('button')
  button.textContent = 'click 1'
  div1.appendChild(button)
},1000) //产生一个button,button内容,把button放到div1里面

  
div1.addEventListener('click',(e)=>{
const t=e.target//把t记为被用户操作的元素
if (t.tagName.toLowerCase() ==='button'){
  console.log('button被click')
}
});  
</script>
  1. 封装事件委托
<div id="div1">
</div>
<script>
setTimeout(()=>{
  const button = document.creatElement('button')
  button.textContent = 'click 1'
  div1.appendChild(button)
},1000) 

 on('click','#div1','button',()=>{
 console.log('button被点击了')
 })  
  
 function on(eventType, element, selector, fn){
   //判断如果element不是元素
   if(!(element instanceof Element)){
    element = document.querySelector(element)
   }
 element.addEventListener(eventType,(e)=>{
 const t = e.target
 if(t.matches(selector)){//matches用来判断一个元素是否满足选择器
    fn(e)
 }
 })
 }