DOM事件和事件委託

DOM事件

DOM事件分爲捕獲階段,事件階段和冒泡階段。程序員

咱們能夠看到,其執行順序爲,捕獲 => 目標 => 冒泡api

因此,若是用戶點擊了td元素,而且,td元素的祖先元素擁有監聽函數,那麼其祖先元素也算被點擊了。bash

可是,若是被點擊的元素沒有父元素,且他被用戶點擊了,那麼,冒泡與捕獲的順序取決於JS代碼的順序dom

上文提到,DOM事件擁有捕獲和冒泡階段,那麼監聽函數會不會被調用兩次呢?函數

答案是不會,W3C 制定了一個標準,其api爲ui

xxx.addEventListener('eventType',fn,bool)
複製代碼

若bool爲falsy值或不傳(0,'',NaN,undefined,null),那麼,綁定爲冒泡,若爲true則爲捕獲。spa

須要特別注意的是,若是咱們須要延遲觸發事件3d

那麼直接監聽,是監聽不到事件的,由於1s後,點擊事件已經結束了,因此咱們須要將點擊事件記錄下來。code


target VS currentTarget

target 與 currentTarget 的區別在於,target是用戶操做的元素,currentTarget是程序員監聽的元素。cdn

例如 div>span{文字},那麼用戶點擊文字

span就是target

div就是currentEvent


冒泡的取消

一般狀況下,咱們能夠經過stopPropagation阻止冒泡(捕獲沒法被取消)。

(例如當咱們點擊一個內部標籤時,不想觸發外部標籤的事件,可使用這種方法)

例如,scroll 事件就沒法取消冒泡,因此咱們只能經過其餘辦法取消,例如使滾動條的寬度爲0,阻止滾輪的默認事件,阻止移動端touchstart的默認事件。


自定義事件

dom事件類型有不少,具體咱們能夠參考MDN

button1.addEventLsitener('click',()=>{
    const event = new CustomEvent('name',{
        {'detail':{name:'jack',age:'18'}},
        bubbles:true,
        cancelable:true
    })
    button1.dispatchEvent(event)
})
複製代碼

事件委託

事件委託就是監聽祖先元素,判斷被點擊的元素是不是咱們想監聽的元素,如果,則執行函數。 其優勢是節省內存以及能夠監聽動態生成的元素

function on(eventType,element,selector,fn){
    if(!(element instanceof Element)){
        element = document.querySelector(element)
    }
    
    element.addEventListener(eventType,(e)=>{
        t = e.target
        if (t.tagName.toLowercase() === selector){
            fn(e)
        }
    })
}
複製代碼

若是咱們將事件委託函數封裝成以上形式,咱們會發現一個問題,當用戶點擊時,target不必定是咱們監聽的元素。

因此,咱們須要使用遞歸,來尋找target的祖先元素,直到祖先元素是element爲止。

function on(eventType,element,selector,fn){
    if (!(element instanceof Element)){
        element = document.querySelector(element)
    }
    
    element.addEventListener(eventType,(e)=>{
        let t = e.target
        while(t.tagName.toLowercase() !== selector){
            if(t === element){
                t = null
                break
            }
            t = t.parentNode
        }
        t && fn.call(t,e,t)
    })
    return element
}
複製代碼
相關文章
相關標籤/搜索