click事件在什么时候出发_DOM事件模型

DOM 事件模型是浏览器中一个很重要的功能,它可以让用户与浏览器交互起来,同时 DOM 事件也是前端面试的高频题,这个知识点是必须要掌握的

事件捕获和冒泡

w3c 上有一个图很明确的解释了捕获阶段和冒泡阶段的先后顺序

258facd1caf971572b9ea1808340dc87.png

看到这我知道你还是不知道这个事件模型有什么用,直接上例子

<!DOCTYPE html>
<html>

<head>
  <meta charset="utf-8">
  <title>DOM事件模型</title>
</head>
<style>
  *{
    padding: 0;
    margin: 0;
    box-sizing: border-box;
  }
  div{
    border: 1px solid black;
  }
  .div1{
    margin: 100px;
    padding: 15px;
    width: 90px;
    height: 90px;
    border-radius: 50%;
    background: red;
  }
  .div2{
    padding: 15px;
    width: 60px;
    height: 60px;
    border-radius: 50%;
    background: blue;
  }
  .div3{
    width: 30px;
    height: 30px;
    border-radius: 50%;
    background: green;
  }
  .x{
    background: transparent;
  }
</style>

<body>
  <div class="div1">
    <div class="div2">
      <div class="div3"></div>
    </div>
  </div>
</body>

</html>

这样利用三个 div 实现一个飞镖圆盘,接下来为他们添加点击事件

<script>
  const div1 = document.querySelector('.div1')
  const div2 = document.querySelector('.div2')
  const div3 = document.querySelector('.div3')
  
  div1.addEventListener('click',(e)=>{
    console.log(1)
  })
  div2.addEventListener('click',(e)=>{
    console.log(2)
  })
  div3.addEventListener('click',(e)=>{
    console.log(3)
  })
</script>

打印结果为 3 2 1,可以看到它是从最里面的 div 开始打印,这种顺序叫做冒泡

接下来我们改一下代码

<script>
  const div1 = document.querySelector('.div1')
  const div2 = document.querySelector('.div2')
  const div3 = document.querySelector('.div3')
  
  div1.addEventListener('click',(e)=>{
    console.log(1)
  },true)
  div2.addEventListener('click',(e)=>{
    console.log(2)
  },true)
  div3.addEventListener('click',(e)=>{
    console.log(3)
  },true)
</script>

打印结果为 1 2 3,可以看到它是从最外面的 div 开始打印,这种顺序叫做捕获, 把 addEventListener 第二个参数改为 true 就可以实现捕获(默认为 false 冒泡)

那么不论是捕获或者冒泡,它总该有个终点吧,要不从哪里开始算捕获,而从哪结束冒泡呢

正确答案是按 window -> document -> html -> body -> 元素, 那我怎么知道的呢,请看上图

Event 对象

在事件模型上有一个很重要的 Event 对象,它可以在触发事件的时候存在事件回调函数里,你就可以依据它做出想要的操作

<script>
  const div1 = document.querySelector('.div1')
  
  div1.addEventListener('click',(e)=>{
    console.log(e) // div1 的事件对象
    console.log(e.target) // 点击的 div 元素,不固定
    console.log(e.currentTarget) // 绑定点击事件的元素
  })
</script>

具体这个 e 的属性很多,能做出相应的事也很多,请参考 mdn

自定义事件

事件类型有一百多种,不用全看完,会用几个常用的比如 click,focus,change,input,blur 等,其他事件等需要的时候再去 mdn 查

如果这一百多个事件你都不想用,也可以自定义事件

<script>
    const div1 = document.querySelector('.div1')
    div1.addEventListener('click',()=>{
      const myEvent = new CustomEvent('myEvent',{
        detail:{
          name: 'chauncey'
        }
      })
     div1.dispatchEvent(myEvent)
   })
   div1.addEventListener('myEvent',(e)=>{
     console.log(e.detail.name) // chauncey
   })
 </script>

这样在点击 div1 的时候就会注册一个自定义事件 myEvent,可以设置一些属性在 myEvent 上,这样在监听这个事件的时候就可以打印出相应的属性

事件委托

什么是事件委托,先设置两个场景

  1. 假设你的页面有 100 个按钮,现在需要给每个按钮添加一个点击事件,那么就得 addEventListener 100 次,这样代码很啰嗦而且非常浪费内存
  2. 假设添加事件的元素是 JS 动态生成的,那怎添加事件

这两个场景都不适合直接给元素上添加事件,那么这时候事件委托就来了,它可以很轻松的解决这两个问题

因为事件模型有冒泡机制,在事件触发的时候会一层一层的向上通知,这样触发事件的元素的祖先就会得到通知,我们监听他的祖先就可以实现事件监听

 <script>
    /**
     * delegate 事件委托
     * param event 事件类型
     * param element 监听元素
     * param selector 实际监听元素
     * param fn 回调函数
     * return element 监听元素
     * */
    function delegate(event, element, selector, fn) {
      element.addEventListener(event, (e) => {
        let el = e.target
        while (!el.matches(selector)) {
          if (el === element) {
            el = null
            break
          }
          el = el.parentNode
        }
        el && fn.call(el, e, el)
      })
      return element
    }
 </script>

这样的一个事件委托函数就封装完了,它的原理就是一层一层往上找,如果找不到那就不做操作,如果找到了那就执行回调函数

DOM 事件原型最核心的概念就介绍完了,它还有很多琐碎的知识点也不用专门去了解,知道核心知识就足够应用大部分场景,如果遇到了个别特殊场景再去查 mdn,完

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值