怎么触发子级的点击事件_《DOM事件机制》

一、简介

事件流是一个事件沿着特定数据结构传播的过程。冒泡捕获是事件流在DOM中两种不同的传播方法

事件流有三个阶段

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

事件捕获

事件捕获(event capturing):通俗的理解就是,当鼠标点击或者触发dom事件时,浏览器会从根节点开始由外到内进行事件传播,即点击了子元素,如果父元素通过事件捕获方式注册了对应的事件的话,会先触发父元素绑定的事件

事件冒泡

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

示意图

34f933a41bb7a1a45cfbdcbf61170882.png

二、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>

f68e20298066448171c83887a92a3a13.png

因为在子元素点击事件中使用了event.stopPropagation()阻止冒泡事件,所以最终只打印出了目标元素'hello',父元素的'hi'并没有被打印出

是否可以阻止冒泡

并不是所有事件都可以阻止冒泡的,具体可以MDN搜索scroll event,看到BubblesCancelable

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​都触发事件打印出对应元素的文本内容

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值