DOM 事件与事件委托

点击事件

2002年,W3C 发布标准 DOM Level 2 Events Specification

规定浏览器需要同时支持两种调用顺序:

首先按照爷爷=>爸爸=>儿子的顺序看有没有函数监听

然后按儿子=>爸爸=>爷爷的顺序看有没有函数监听

有监听函数就调用,并提供事件信息,没有就跳过

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

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

DOM 事件与事件委托

addEventListener

事件绑定 API

  • IE5:baba.attchEvent('onclick',fn) // 冒泡
  • 网景:baba.addEventListener('click',fn) // 捕获
  • W3C:baba.addEventListener('click',fn,bool)

如果 bool 为 ture

  • 就让 fn 走捕获,即当浏览器在捕获阶段发现 baba 有 fn 监听参数,就会调用 fn, 并提供事件信息

如果不传 bool 或者为 falsy

  • 就让 fn 走冒泡,即当浏览器在冒泡阶段发现 baba 有 fn 监听参数,就会调用 fn, 并提供事件信息 

代码示例

html

<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8">
  <title>JS Bin</title>
</head>
<body>
<div class="level1 x">
  <div class="level2 x">
  </div>
</div>
</body>
</html>

css

* {
  box-sizing: border-box;
}
div[class^=level] {
  border: 1px solid;
  border-radius: 50%;
  display: inline-flex;
}
.level1 {
  padding: 10px;
  background: purple;
}
.level2 {
  padding: 10px;
  background: blue;
}
.x{
  background: transparent;
}
JS

const level1 = document.querySelector('.level1')
const level2 = document.querySelector('.level2')

let n = 1

level1.addEventListener('click', (e)=>{
  const t = e.currentTarget
  setTimeout(()=>{  
    t.classList.remove('x')
  },n*1000)
  n+=1
})
level2.addEventListener('click', (e)=>{
  const t = e.currentTarget
  setTimeout(()=>{  
    t.classList.remove('x')
  },n*1000)
  n+=1
})

target 和 currentTarget

区别

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

举例

  • div.span{文字}
  • 用户点击文字
  • e.target 就是 span
  • e.currentTarget 就是 div

特例

  • 只有一个 div 被监听(不考虑父子同时被监听)
  • fn 分别在捕获阶段和冒泡阶段监听 click 事件
  • 用户点击的元素就是开发者监听的
  • 这是一个特例,谁先监听谁先执行

取消冒泡

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

不可阻止默认动作

  • 有些事件不能阻止默认动作
  • MDN 搜索 scroll event,看到 Bubbles 和 Cancelable
  • Bubbles 的意思是该事件是否冒泡,所有冒泡都可取消
  • Cancelable 的意思是开发者是否可以阻止默认事件
  • Cancelable 与冒泡无关

如何阻止滚动?

  • scroll 事件不可阻止默认动作
  • 阻止 scroll 默认动作没用,因先有滚动才有滚动事件
  • 要阻止滚动,可阻止 wheel 和 touchstart 的默认动作
  • 需要找准滚动条所在的元素
x.addEventListener('wheel', (e)=>{
  e.preventDefault()
})
x.addEventListener('touchstart', (e)=>{
  e.preventDefault()
})
  • 但是滚动条还能用
  • 可用 CSS 让滚动条 width: 0 
::-webkit-scrollbar{
   width:0 !important
}
  • 或者用 CSS 使用 overflow: hidden
  • 可以直接取消滚动条,但此时JS依然可以修改 scrollTop

自定义事件

  • 浏览器自带事件,一共100多种,详细列表见 MDN
  • 开发者可以在自带事件之外,自定义事件

事件委托

如何给100个按钮添加点击事件?

答:监听这100个按钮的祖先,等冒泡的时候判断 target 是不是这100个按钮中的一个

如何监听目前不存在的元素的点击事件?

答:监听祖先,等点击的时候看看是不是想要监听的元素

优点

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

JS 是否支持事件?

  • 支持也不支持,DOM 事件不属于 JS 的功能,属于浏览器提供的 DOM 的功能
  • JS只是调用了 DOM 提供的 addEventListener 而已

 *本文为鲲游北冥的原创文章,著作权归本人和饥人谷所有,转载务必注明来源

上一篇:鼠标右键点击事件


下一篇:事件的绑定和移除