DOM事件與事件委託

DOM事件

DOM事件包括100多種,包括點擊事件等。這些事件能夠事件捕獲和事件冒泡,事件捕獲的特色是從外到內監聽函數,即從父親到兒子;事件冒泡的特色是從內到外監聽函數,即從兒子到父親。程序員能夠決定使用事件捕獲仍是事件冒泡。程序員

程序員如何決定捕獲仍是冒泡

捕獲事件web

元素.addEventListener('click',fn,不傳參或者falsy)
複製代碼

冒泡事件瀏覽器

元素.addEventListener('click',fn,true)
複製代碼

題外話

CSS:給class屬性以level開頭的每個div元素bash

div[class^=level]{
    //添加CSS屬性
}
複製代碼

實例:使用冒泡事件監聽click

level1.addEventListener('click',(e)=>{
   //將傳入對象e暫存
   const t=e.currentTarget
   setTimeout(()=>{
       //點擊時去掉自身的.x
       t.classList.remove('x')
   },n*1000)
   n+=1
},true)
複製代碼

函數的結構:fn裏面有3個函數,第一個是將參數e暫存,爲何須要暫存:由於e只存在點擊的一瞬間,執行setTimeout裏面時,e已經消失,不會執行;第二個參數是1秒後再執行;第三個是將n加1,不至於全部的鬧鐘一塊兒響app

捕獲事件和冒泡事件如何一塊兒作

level1.addEventListener('click',(e)=>{
    //將參數e暫存
    const t=e.currentTarget
    setTimeout(()=>{
        //點擊時將自身的.x去掉
    t.classList.remove('x')
    },n*1000)
    n+=1
},true)

level1.addEventListener('click',(e)=>{
    //將參數e暫存
    const t=e.currentTarget
    setTimeout(()=>{
        //點擊時將自身的.x去掉
    t.classList.add('x')
    },n*1000)
    n+=1
},false)
複製代碼

target與cruurentTarget的區別

  • e.target——用戶操做的元素
  • e.currentTarget——程序員監聽的元素
  • this指向e.currentTarget,因爲很差記,不推薦使用this

舉例:

<div>
 <span>文字</span>
</div>
複製代碼
當用戶點擊了文字,e.target就是span,e.currentTarget就是div
複製代碼

捕獲、冒泡的前後順序

W3C的事件模型:先捕獲(先爸爸後兒子),再冒泡(先兒子再爸爸)。注意,e對象傳給全部監聽函數,監聽事件結束後,能夠認爲e對象不存在。函數

特例

當用戶操做的元素就是開發者監聽的元素,fn分別在捕獲階段和冒泡階段監聽click事件ui

div.addEventListener('click',f1)    //捕獲事件
div.addEventListener('click',f2,true)  //冒泡事件
複製代碼

請問,先執行哪一個事件? 誰先監聽,就先執行哪一個this

如何取消冒泡及冒泡屬性

捕獲事件不能取消,可是冒泡能夠取消。e.stopPropagation()能夠中斷冒泡,瀏覽器再也不往上走,通常用於封裝某些獨立的組件,Bubbles屬性是該事件是否冒泡,Cancelable的屬性是開發者是否能夠取消冒泡spa

如何阻止頁面滾動

<div id="x">
  ………………
</div>
複製代碼

第一:阻止滾輪滾動code

x.addEventListener("wheel",
 (e)=>{
     e.preventDefault()
 }
)
複製代碼

第二:阻止鼠標滾動,設置CSS

::-webkit-scrollbar{
    width:0 !improtant
}
複製代碼

第三:阻止手機的觸屏滾動

x.addEventListener('touchstart',
  (e)=>{
      e.preventDefault()
  }
)
複製代碼

自定義DOM事件:自定義一個frank事件,而且能冒泡,可是不能阻止冒泡

HTML:

<div id="div1">
       <button id="button1">
         點擊觸發frank事件
       </button>
    </div>
複製代碼

JavaScript:

button1.addEventListener('click',()=>{
   //聲明自定義事件
   const event = new CustomEvent('frank',{
   //自定義事件的信息
   detail:{name:'frank',age:18},
   //能夠冒泡
   bubbles:true,
   //不能阻止冒泡
   cancelable:false
   })
   //讓button1觸發事件,至關於調用
   button1.dispatchEvent(event)
}))

//監聽button1
button1.addEventListener('frank',(e)=>{
   console.log(e.detail)
})
複製代碼

事件委託

特定情景一

<div id="div1">
  …………中間有100個button標籤
</div>
複製代碼

請問,若是給100個button標籤添加點擊事件,怎麼作?
思路:監聽它們的祖先元素div,等冒泡的時候判斷target是否是這100個按鈕中的一個。
作法:

div1.addEventListener('click',(e)=>{
   const t=e.target
   if(t.tagName.toLowerCase()=== 'button'){
       console.log('button 被點擊了')
       console.log('button內容是'+t.textContent)
   }
})
複製代碼

體現出事件委託的優勢:省監聽數(省內存)

特定情景二

若是監聽目前不存在的元素的點擊事件,怎麼作?
思路:監聽祖先元素,等點擊的時候看看是否是我想要監聽的元素。
作法:

//1秒鐘以後,在div裏面建立button
setTimeout(()=>{
   //建立button按鈕
   const button=document.createElement('button')
   //button按鈕裏面文本
   button.textContent='click 1'
   //向div1裏面添加子節點button
   div1.appendChild(button)
},1000)

//監聽button元素1秒鐘以後是否被用戶點擊
div1.addEventListener('click',(e)=>{
    //獲取用戶操做的元素
   const t=e.target
   if(t.tagName.toLowerCase() === 'button'){
       console.log('button 被click')
   }
})
複製代碼

體現出事件委託的優勢:能夠動態監聽元素

封裝一個事件委託:事件委託就是監聽祖先元素,等咱們點擊時來判斷它是否是咱們要監聽的元素,是的話執行函數

用戶只須要經過on事件,監聽div下面的button是否被點擊

on('click','#div1','button',()=>{
    console.log('button被點擊了')
})

function on(eventType,element,selector,fn){
    //若是element不是一個元素,就獲取element所在的元素
    if(!(element instanceof Element)){
        element=document.querySelector(element)
    }
    
    element.addEventListener(eventType,(e)=>{
        const t=e.target
        //matches判斷一個元素是否知足一個選擇器
        if(t.matches(selector)){
            fn(e)
        }
    })
}
複製代碼

注意

上面的事件委託是DOM事件,DOM是由瀏覽器提供的,JS只是調用了DOM提供的addEventListener。

相關文章
相關標籤/搜索