JS事件流总结

150 阅读3分钟

事件流

​ 定义: 每个事件发生时,都有一个触发并执行的过程,也就是事件的传播过程,我们称之为事件流,简单地说事件流就是事件从触发到执行结束的流程

​ 事件流的三个阶段

  • 捕获阶段

    事件从顶级元素触发,然后逐渐向下传播,直到目标元素,依次执行其身上绑定的事件

  • 目标阶段

    触发当前自身的事件

  • 冒泡阶段

    事件由目标元素接收,然后逐渐向上传播,达到最顶层元素,依次执行其身上绑定的事件

事件流模型

事件执行的流程是

  • 捕获阶段 ---> 目标阶段 ---> 冒泡阶段
  • 目标元素的事件是在目标阶段执行,其它事件会在冒泡阶段执行。每个事件只会执行一次,也就是说如果在冒泡阶段执行了事件,就不会在捕获阶段执行


事件级别

DOM标准:

类似于 ES6 和 ES5 版本变更

  • DOM0

    事件处理函数绑定

      <body>
          <button id="box">box</button>
          <script>
              box.onclick = function(){
                  console.log("我是box");
              }
          </script>
      </body>
    
  • DOM1

    没有定义相关事件的写法

  • DOM2

    新增addEventListene(type,callback,useCapture)

      small.addEventListener('click',function(){
          console.log(this);
      })
    

    注意:useCapture

  • DOM3 DOM4


事件委托

事件对象

  • 兼容性处理

      small.addEventListener('click',function(ev){
          var e = ev || window.event
      },true)
    
  • 事件对象常用属性

    • e.type

    • e.target

      选中的元素(点击就是点击元素,划入就是划入元素)

    存在兼容性问题

      var target = e.target || e.srcElement
    
    • e.cueerntTarget

      绑定事件处理函数对应的的DOM元素

      small.addEventListener('click',function(ev){
          var e = ev || window.event
          console.log(e.type);  // 事件类型
      },true)
    

    target和currentTarget的区别是:

    1. target:触发事件的元素currentTarget:事件绑定的元素
    2. 两者在没有冒泡的情况下,是一样的值,但在用了事件委托的情况下,就不一样了

案列

一个ul里面包括几百个li,如果给每个li都绑定事件,十分耗费性能,通过事件委托,给父级元素绑定一个事件,通过冒泡机制和e.target判断是那个li被触发了

  <body>
      <ul id='box'>
          <li>1</li>
          <li>2</li>
          <li>3</li>
          <li>4</li>
          <li>5</li>
      </ul>
  ​
      <script>
          box.onclick = function(e){
              var target = e.target || e.srcElement
              console.dir(target.innerHTML);
          }
      </script>
  </body>

取消事件冒泡 和 捕获

w3c的方法是e.stopPropagation(),IE则是使用e.cancelBubble = true

​ e. bubbles属性值

  e.bubbules //true代表可以冒泡 false达标不可以冒泡
  ​
  js中基本所有事件都可以冒泡,除了
  1. focus
  2. onblur
  3. onSroll
  • stopPropagation

    • stopPropagation:阻止冒泡和捕获
      big.addEventListener('click',function(ev){
          var e = ev || window.event
          console.log('outer');
      })
      ​
      small.addEventListener('click',function(ev){
          var e = ev || window.event
          e.stopPropagation()  # 阻止冒泡,不能阻止多个事件,如果small绑定了多个函数
          console.log('inner1');
      })
      ​
      small.addEventListener('click',function(ev){
          var e = ev || window.event
          e.stopPropagation()  # 阻止冒泡,不能阻止多个事件,如果small绑定了多个函数
          console.log('inner2');
      })
    
  • stopImmediatePropagation

    • 不仅可以取消冒泡和捕获,还可以取消同一个事件的其它监听函数被调用

        big.addEventListener('click',function(ev){
            var e = ev || window.event
            console.log('outer');
        })
        ​
        small.addEventListener('click',function(ev){
            var e = ev || window.event
            e.stopImmediatePropagation()
            console.log('inner1');
        })
        ​
        small.addEventListener('click',function(ev){
            var e = ev || window.event
            console.log('inner2');
        })
      
  • cancleBubble

      big.addEventListener('click',function(ev){
          var e = ev || window.event
          console.log('outer');
      })
      ​
      small.addEventListener('click',function(ev){
          var e = ev || window.event
          e.cancelBubble = true
          console.log('inner1');
      })
    

兼容性处理方案

  function cancelBubble(e){
      var e = e || window.event
      if(e.stopPropagation){
          e.stopPropagation()
      }else{
          e.cancelBubble = true
      }
  }

注意事项

  • 所有事件都会冒泡到window上吗?

    现代浏览器 IE9+