事件

1.解釋以下概念:事件傳播機制、阻止傳播、取消默認事件、事件代理

  • 基礎

    什么是事件?
    JavaScript和HTML的交互是通過事件實現(xiàn)的。事件是某個行為或者觸發(fā),比如點擊、鼠標移動,圖片加載等。
    什么是事件流
    事件流描述的是從頁面中接收事件的順序。當用戶點擊了一個有嵌套關系的元素時,那是先點擊的是用戶本身想要點擊的被嵌套的元素,還是嵌套元素的父元素?這里有三種事件傳播的模型:事件冒泡,事件捕獲,DOM事件流。
    1.事件冒泡:事件開始時由最具體的元素接收,然后逐級向上傳播到較為不具體的元素

    事件冒泡

    2.事件捕獲:不太具體的節(jié)點更早接收事件,而最具體的元素最后接收事件,和事件冒泡相反(ie低版本沒有捕獲)
    事件捕獲

    3.DOM事件流:DOM2級事件規(guī)定事件流包括三個階段,事件捕獲階段,處于目標階段,事件冒泡階段,首先發(fā)生的是事件捕獲,為截取事件提供機會,然后是實際目標接收事件,最后是冒泡階段
    DOM事件流

  • 事件傳播機制

當一個事件發(fā)生以后,它會在不同的DOM節(jié)點之間傳播。這種傳播分為三個階段:


事件傳播機制
  • 第一階段,“捕獲階段”。:事件從document開始向下傳,一直傳到觸發(fā)的目標節(jié)點上,在這個過程中會依次檢測是否有節(jié)點綁定了事件的監(jiān)聽函數(shù),如果有就會執(zhí)行。
  • 第二階段,目標階段:事件到達目標節(jié)點,并且觸發(fā)監(jiān)聽函數(shù)。
  • 第三階段,冒泡階段:從目標節(jié)點依次上傳,直到document,再依次判斷是否有節(jié)點綁定了監(jiān)聽函數(shù)。
    這種三階段的傳播模型,會使得一個事件在多個節(jié)點上觸發(fā),比如會在捕獲階段和冒泡階段在一個節(jié)點上執(zhí)行兩次。
  • 阻止傳播

如果有特殊情況,需要事件在某個節(jié)點上停止傳播,就可以使用stopPropagation()取消事件進一步捕獲或冒
泡,防止再觸發(fā)定義在別的節(jié)點上的監(jiān)聽函數(shù),但是不包括在當前節(jié)點上新定義的事件監(jiān)聽函數(shù)

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

取消瀏覽器對當前事件的默認行為,像有些元素時有默認的事件的,比如<a>標簽,在點擊的時候默認會打開所含的超鏈接。如果想要自定義點擊<a>鏈接的操作,就可以通過preventDefault()取消事件默認行為

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

由于事件會在冒泡階段向上傳播到父節(jié)點,因此可以把子節(jié)點的監(jiān)聽函數(shù)統(tǒng)一處理。指定一個事件處理程序,就可以管理某一類型的所有事件

document.querySelector('ul').addEventListener('click', function(event){
    if(event.target.tagName.toLowerCase() === 'li'){   //或者if(e.target.classList.contains('box'))用class來選擇
        //監(jiān)聽ul下面的所有l(wèi)i
    }
})

如果之后再在ul里面添加li,監(jiān)聽函數(shù)也可以監(jiān)聽新增的li

2.寫一個 Demo,演示事件傳播的過程,演示阻止傳播的效果

捕獲階段還是冒泡階段,可以通過addEventListener第三個參數(shù)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在被點擊的時候觸發(fā)兩個事件,此時第二個監(jiān)聽函數(shù)會覆蓋第一個,最后的輸出 結果只有2
這個時候不要把onclick當成一個觸發(fā)時間,要把它看成一個“屬性”,那么后面的“屬性”會覆蓋掉前面的“屬性”

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

因為選擇的是一個數(shù)組,沒有onclick,除非用數(shù)組的forEach去遍歷每一個數(shù)組,但是寫起來又特別的麻煩

DOM2級事件定義了兩個方法用于處理指定和刪除事件處理程序的操作:
addEventListener
removeEventListener
所有的DOM節(jié)點都包含這兩個方法,并且它們都接受三個參數(shù):
1.事件類型
2.事件處理方法
3.布爾參數(shù),如果是true表示在捕獲階段調用事件處理程序,如果是false,則是在事件冒泡階段處理
這時,想要實現(xiàn)上面的效果就很容易了

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){   //監(jiān)聽點擊
    if(s.target.tagName.toLowerCase() === 'li'){
      console.log(s.target.innerText)
    }
  })
</script>

5.onlick與addEventListener的區(qū)別

  • onclick事件在同一時間只能指向唯一對象
  • addEventListener給一個事件注冊多個listener
  • addEventListener對任何DOM都是有效的,而onclick僅限于HTML
  • addEventListener可以控制listener的觸發(fā)階段(捕獲/冒泡)。對于多個相同的事件處理器,不會重復觸發(fā),不需要手動使用removeEventListener清除
  • IE9使用attachEvent和detachEvent
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
【社區(qū)內容提示】社區(qū)部分內容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發(fā)布,文章內容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內容

  • 以下文章為轉載,對理解JavaScript中的事件處理機制很有幫助,淺顯易懂,特分享于此。 什么是事件? 事件(E...
    jxyjxy閱讀 3,171評論 1 10
  • 事件是一種異步編程的實現(xiàn)方式,本質上是程序各個組成部分之間的通信。DOM支持大量的事件,本節(jié)介紹DOM的事件編程。...
    許先生__閱讀 1,030評論 0 3
  • 事件是一種異步編程的實現(xiàn)方式,本質上是程序各個組成部分之間的通信。DOM支持大量的事件,本節(jié)介紹DOM的事件編程。...
    周花花啊閱讀 678評論 0 3
  • 一、問答 1. dom對象的innerText和innerHTML有什么區(qū)別? innerHTML: 也就是從對象...
    饑人谷_羅偉恩閱讀 699評論 0 2
  • 前言 本文主要介紹: DOM事件級別 DOM事件流 DOM事件模型 事件代理 Event對象常見的方法和屬性 一、...
    xyyojl閱讀 1,342評論 0 3

友情鏈接更多精彩內容