天天看点

addeventlistener事件第三个参数_《DOM事件机制》

一、简介

事件流是一个事件沿着特定数据结构传播的过程。

冒泡

捕获

是事件流在DOM中两种不同的

传播方法

事件流有三个阶段

  • 事件捕获阶段
  • 处于目标阶段
  • 事件冒泡阶段

事件捕获

事件捕获(

event capturing

):通俗的理解就是,

当鼠标点击或者触发

dom

事件时,浏览器会从根节点开始由外到内进行事件传播,即点击了子元素,如果父元素通过事件捕获方式注册了对应的事件的话,会先触发父元素绑定的事件

事件冒泡

事件冒泡(

dubbed bubbling

):与事件捕获恰恰相反,事件冒泡顺序是由内到外进行事件传播,直到根节点

示意图

addeventlistener事件第三个参数_《DOM事件机制》

二、W3C事件模型

因为有捕获和冒泡两种传播方式,W3C制定了一个标准可以让我们自己选择使用哪种传播方式

addEventListener('click',fn,?)

第三个参数

?

是一个

bool

值,决定使用捕获或者冒泡

举个例子

<div>
  <p>点我看效果</p> 
</div>
           

当你

addEventListener

函数

第三个参数为

true

时就表示你使用的是

事件捕获

。父级元素先触发,子级元素后触发,也就是说

div

先触发,

p

后触发。

当你

addEventListener

函数

第三个参数为空或为

false

时就表示你使用的是

事件冒泡

。子级元素先触发,父级元素后触发,也就是说

p

先触发,

div

后触发。

三、Event对象常见的应用

event. preventDefault()阻止默认事件

如果调用这个方法,默认事件行为将不再触发。

什么是默认事件呢?例如表单一点击提交按钮(

submit

)跳转页面、

a

标签默认页面跳转或是锚点定位等。

很多时候我们使用

a

标签仅仅是想当做一个普通的按钮,点击实现一个功能,不想页面跳转,也不想锚点定位。

<a id='a' href='https://baidu.com'>百度</a>
  
<script>
  a.addEventListener("click", function(e){
    e.preventDefault();
     }); 
</script>
           

我们给

a

添加点击事件,当用户点击

百度

就阻止

a

标签的默认事件,所以点击后不会有跳转

event.stopPropagation()阻止事件冒泡

上面提到事件冒泡阶段是指事件从目标节点自下而上向

window

对象传播,当事件使用

event.stopPropagation()

方法将阻止事件冒泡到父元素,阻止任何父事件处理程序被执行

<div id="hi" style="border: 1px solid red; width: 100px; height: 100px;">
    <div id="hello" style="border: 1px solid red; width: 50px; height: 50px;"></div>
</div>

<script>
hi.addEventListener("click", function(){
  console.log('hi')
});

hello.addEventListener("click", function(e){
  console.log('hello')
  e.stopPropagation()
});
</script>
           
addeventlistener事件第三个参数_《DOM事件机制》

因为在子元素点击事件中使用了

event.stopPropagation()

阻止冒泡事件,所以最终只打印出了目标元素

'hello'

,父元素的

'hi'

并没有被打印出

是否可以阻止冒泡

并不是所有事件都可以阻止冒泡的,具体可以

MDN

搜索

scroll event

,看到

Bubbles

Cancelable

Bubbles

的意思是该事件是否冒泡

Cancelable

的意思是开发者是否可以阻止冒泡

event.target & event.currentTarget

  • e.target

    指向事件触发的元素
  • e.currentTarget

    指向事件绑定的元素

四、事件委托

由于事件会在冒泡阶段向上传播到父节点,因此可以把子节点的监听函数定义在父节点上,由父节点的监听函数统一处理多个子元素的事件。这种方法叫做事件委托

优点

减少内存消耗,提高性能

假设有一个​

div

​,​

div

​里有大量的​

button

​,我们需要在点击每个​

button

​的时候响应一个事件

<div id="container">
    <button>1</button>
    <button>2</button>
    <button>3</button>
    <button>4</button>
    <button>5</button>
  </div>
           

如果给每个​

button

​都绑定一个函数,那对于内存消耗是非常大的。借助事件代理,我们只需要给父容器

div

绑定方法即可,这样不管点击的是哪一个后代元素,都会根据冒泡传播的传递机制,把容器的

click

行为触发,然后把对应的方法执行,根据事件源,我们可以知道点击的是谁,从而完成不同的事。

动态绑定事件

在很多时候,我们需要通过用户操作动态的增删子元素,如果一开始给每个子元素绑定事件,那么在列表发生变化时,就需要重新给新增的元素绑定事件,给即将删去的元素解绑事件,如果用事件委托就会省去很多这样麻烦。

实现

接下来我们来实现上例中父层元素 ​

#container

​ 下的​

button

​元素的事件委托到它的父层元素上:

<div id="container">
  <button>1</button>
  <button>2</button>
  <button>3</button>
  <button>4</button>
  <button>5</button>
</div>

<script>
container.addEventListener('click', function (e) { 
  //把目标元素赋给t
  let t = e.target
  // 判断是否匹配目标元素
  if (t.nodeName.toLocaleLowerCase() === 'button') {
    console.log('我是:' + t.textContent);
  }
});
</script>
           

这样当点击每个​

button

​都触发事件打印出对应元素的文本内容

继续阅读