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
}
复制代码
相关文章
相关标签/搜索