事件

1.解释以下概念:事件传播机制、阻止传播、取消默认事件、事件代理

  • 基础

    什么是事件
    JavaScript和HTML的交互是通过事件实现的。事件是某个行为或者触发,比如点击、鼠标移动,图片加载等。
    什么是事件流
    事件流描述的是从页面中接收事件的顺序。当用户点击了一个有嵌套关系的元素时,那是先点击的是用户本身想要点击的被嵌套的元素,还是嵌套元素的父元素?这里有三种事件传播的模型:事件冒泡,事件捕获,DOM事件流。
    1.事件冒泡:事件开始时由最具体的元素接收,然后逐级向上传播到较为不具体的元素

    事件冒泡

    2.事件捕获:不太具体的节点更早接收事件,而最具体的元素最后接收事件,和事件冒泡相反(ie低版本没有捕获)
    事件捕获

    3.DOM事件流:DOM2级事件规定事件流包括三个阶段,事件捕获阶段,处于目标阶段,事件冒泡阶段,首先发生的是事件捕获,为截取事件提供机会,然后是实际目标接收事件,最后是冒泡阶段
    DOM事件流

  • 事件传播机制

当一个事件发生以后,它会在不同的DOM节点之间传播。这种传播分为三个阶段:


事件传播机制
  • 第一阶段,“捕获阶段”。:事件从document开始向下传,一直传到触发的目标节点上,在这个过程中会依次检测是否有节点绑定了事件的监听函数,如果有就会执行。
  • 第二阶段,目标阶段:事件到达目标节点,并且触发监听函数。
  • 第三阶段,冒泡阶段:从目标节点依次上传,直到document,再依次判断是否有节点绑定了监听函数。
    这种三阶段的传播模型,会使得一个事件在多个节点上触发,比如会在捕获阶段和冒泡阶段在一个节点上执行两次。
  • 阻止传播

如果有特殊情况,需要事件在某个节点上停止传播,就可以使用stopPropagation()取消事件进一步捕获或冒
泡,防止再触发定义在别的节点上的监听函数,但是不包括在当前节点上新定义的事件监听函数

document.querySelector('#box') = function(e){
e.stopPropagation() //阻止传播
}
  • 取消默认事件

取消浏览器对当前事件的默认行为,像有些元素时有默认的事件的,比如<a>标签,在点击的时候默认会打开所含的超链接。如果想要自定义点击<a>链接的操作,就可以通过preventDefault()取消事件默认行为

document.querySelector('a') = function(e){
e.preventDefault() //阻止默认事件
}
  • 事件代理

由于事件会在冒泡阶段向上传播到父节点,因此可以把子节点的监听函数统一处理。指定一个事件处理程序,就可以管理某一类型的所有事件

document.querySelector('ul').addEventListener('click', function(event){
    if(event.target.tagName.toLowerCase() === 'li'){   //或者if(e.target.classList.contains('box'))用class来选择
        //监听ul下面的所有li
    }
})

如果之后再在ul里面添加li,监听函数也可以监听新增的li

2.写一个 Demo,演示事件传播的过程,演示阻止传播的效果

捕获阶段还是冒泡阶段,可以通过addEventListener第三个参数cancelable属性来控制。默认是falsse为冒泡阶段,可以设置为true变成捕获阶段

html+css
<style> 
    .container,
    .box,
    .target{
      border: 1px solid;
      padding: 10px;
    }  
  </style>
  <button id="btn">click</button>

  <div class="container">
    container
    <div class="box">
      box
      <div class="target">target</div>
    </div>
  </div>
js
<script>
  var $ = function(e){
    return document.querySelector(e)
  }
  $('.container').addEventListener('click',function(){
    console.log('container 捕获阶段')
  },true)
  $('.box').addEventListener('click',function(){
    console.log('box 捕获阶段')
  },true)
  $('.target').addEventListener('click',function(){
    console.log('target 捕获阶段')
  },true)
   $('.target').addEventListener('click',function(){
    console.log('target 冒泡阶段')
  },false)
  $('.box').addEventListener('click',function(){
    console.log('box 冒泡阶段')
  },false)
  $('.container').addEventListener('click',function(){
    console.log('container 冒泡阶段')
  },false)
//正常点击target  输出
//container 捕获阶段
//box 捕获阶段
//target 捕获阶段
//target 冒泡阶段
//box 冒泡阶段
//container 冒泡阶段
</script>
如果想让事件在 box冒泡阶段 停止
<script>
  var $ = function(e){
    return document.querySelector(e)
  }
  $('.container').addEventListener('click',function(){
    console.log('container 捕获阶段')
  },true)
  $('.box').addEventListener('click',function(){
    console.log('box 捕获阶段')
  },true)
  $('.target').addEventListener('click',function(){
    console.log('target 捕获阶段')
  },true)
   $('.target').addEventListener('click',function(){
    console.log('target 冒泡阶段')
  },false)
  $('.box').addEventListener('click',function(e){
    e.stopPropagations()  //这里不能用this 
    console.log('box 冒泡阶段')
  },false)
  $('.container').addEventListener('click',function(){
    console.log('container 冒泡阶段')
  },false)
//container 捕获阶段
//box 捕获阶段
//target 捕获阶段
//target 冒泡阶段
//box 冒泡阶段
</script>

3.解释DOM2事件传播机制

如果用单独的事件绑定,比如

document.querySelector('.button').onclick = function(){
  console.log('1')
}
document.querySelector('.button').onclick = function(){
  console.log('2')
}
//2

想让.button在被点击的时候触发两个事件,此时第二个监听函数会覆盖第一个,最后的输出 结果只有2
这个时候不要把onclick当成一个触发时间,要把它看成一个“属性”,那么后面的“属性”会覆盖掉前面的“属性”

<ul>
  <li class="box">box1</li>
  <li class="box">box2</li>
</ul>
document.querySelectorAll('.box').onclick = function(){
    console.log(this.innerText)
  }
//一个都输出不了

因为选择的是一个数组,没有onclick,除非用数组的forEach去遍历每一个数组,但是写起来又特别的麻烦

DOM2级事件定义了两个方法用于处理指定和删除事件处理程序的操作:
addEventListener
removeEventListener
所有的DOM节点都包含这两个方法,并且它们都接受三个参数:
1.事件类型
2.事件处理方法
3.布尔参数,如果是true表示在捕获阶段调用事件处理程序,如果是false,则是在事件冒泡阶段处理
这时,想要实现上面的效果就很容易了

document.querySelector('.button').addEventListener('click', function(){
  console.log('1')
},false)
document.querySelector('.button').addEventListener('click', function(){
  console.log('2')
},false)
//1
//2

4.补全代码

要求:

  • 当点击按钮开头添加时在<li>这里是</li>元素前添加一个新元素,内容为用户输入的非空字符串;当点击结尾添加时在最后一个 li 元素后添加用户输入的非空字符串.
  • 当点击每一个元素li时控制台展示该元素的文本内容。
<ul class="ct">
  <li>这里是</li>
  <li>饥人谷</li>
  <li>任务班</li>
</ul>
<input class="ipt-add-content" placeholder="添加内容"/>
<button id="btn-add-start">开头添加</button>
<button id="btn-add-end">结尾添加</button>
<script>
//你的代码
</script>
<script>
  var $ = function(e){
    return document.querySelector(e)
  }
  
  var ct = $('.ct')
  var addstr = $('#btn-add-start')
  var addend = $('#btn-add-end')
  var input = $('.ipt-add-content')
  
  addstr.onclick = function(){
    if(input.value !== ''){
      var box = document.createElement('li')
      box.innerText = input.value
      ct.insertBefore(box, ct.firstChild)
    }
  }
  
  addend.onclick = function(){
    if(input.value !== ''){
      var box = document.createElement('li')
      box.innerText = input.value
      ct.appendChild(box)
    }
  }
  
  $('.ct').addEventListener('click', function(s){   //监听点击
    if(s.target.tagName.toLowerCase() === 'li'){
      console.log(s.target.innerText)
    }
  })
</script>

5.onlick与addEventListener的区别

  • onclick事件在同一时间只能指向唯一对象
  • addEventListener给一个事件注册多个listener
  • addEventListener对任何DOM都是有效的,而onclick仅限于HTML
  • addEventListener可以控制listener的触发阶段(捕获/冒泡)。对于多个相同的事件处理器,不会重复触发,不需要手动使用removeEventListener清除
  • IE9使用attachEvent和detachEvent
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容

  • 以下文章为转载,对理解JavaScript中的事件处理机制很有帮助,浅显易懂,特分享于此。 什么是事件? 事件(E...
    jxyjxy阅读 8,161评论 1 10
  • 事件是一种异步编程的实现方式,本质上是程序各个组成部分之间的通信。DOM支持大量的事件,本节介绍DOM的事件编程。...
    许先生__阅读 4,489评论 0 3
  • 事件是一种异步编程的实现方式,本质上是程序各个组成部分之间的通信。DOM支持大量的事件,本节介绍DOM的事件编程。...
    周花花啊阅读 3,736评论 0 3
  • 一、问答 1. dom对象的innerText和innerHTML有什么区别? innerHTML: 也就是从对象...
    饥人谷_罗伟恩阅读 3,803评论 0 2
  • 前言 本文主要介绍: DOM事件级别 DOM事件流 DOM事件模型 事件代理 Event对象常见的方法和属性 一、...
    xyyojl阅读 5,013评论 0 3