javascript事件委托(事件代理)

1.原理:

事件委托就是利用事件冒泡机制指定一个事件处理程序,来管理某一类型的所有事件。

即:利用冒泡的原理,把事件加到父级上,触发执行效果。

好处:

  • 只在内存中开辟了一块空间,节省资源同时减少了DOM操作,提供性能
  • 对于新添加的元素也会有之前的事件原

事件委托原理我们理解了,现在我们先来理解一下事件流,事件流有事件捕获和事件冒泡的阶段,其实也可以理解为三个阶段,事件捕获-->目标对象事件(target)-->事件冒泡阶段, 用下面这张图来理解清晰明了(网上的图):

javascript事件委托(事件代理)_第1张图片

1.事件捕获,当一个事件触发后,从window对象触发,不断经过下级节点。在事件到达目标节点之前的过程就是捕获阶段。所有经过的节点都会触发对应的事件。

2.事件冒泡,当事件到达目标节点后,会沿着捕获阶段的路线,原路返回。同样,所有经过的节点,都会触发对应的事件。

W3C标准中的事件添加方法:addEventListener(type,fn,useCapture);中的第三个参数就是指事件是在哪个阶段触发,可选参数,默认为false。true:事件句柄在捕获阶段执行;false:事件句柄在冒泡阶段执行。

2.JQ的事件委托实现

我们首先来看一看jQuery的事件委托是怎么做的。

jq有个on添加事件的方法,也可以做事件委托。使用 on() 方法添加的事件处理程序适用于当前及未来的元素(比如由脚本创建的新元素)。

使用:

$(selector).on(event,childSelector,data,function) 

参数 说明:

参数 描述
event 必需。规定要从被选元素移除的一个或多个事件或命名空间。

由空格分隔多个事件值,也可以是数组。必须是有效的事件。
childSelector 可选。规定只能添加到指定的子元素上的事件处理程序(且不是选择器本身,比如已废弃的 delegate() 方法)。
data 可选。规定传递到函数的额外数据。
function 可选。规定当事件发生时运行的函数。

重点是上面的参数可以指定为该事件使用的事件代理,就是代理子元素事件的父级节点。childSelector就是目标元素,即点击了这个childSelector元素,触发事件,但是什么时候处理执行事件方法呢,是事件冒泡到selector节点的时候执行事件回调函数。

举个栗子:

$('body').on('click','.btns',function(){
    //do something
    console.log(123);
})

 上面的栗子是说,我页面上所有现有的或者动态新添加的含有btn类的元素的点击事件,都委托给body元素处理,即点击含有btn类的元素要到事件捕获再冒泡到body元素上才执行事件回调。

3.原生JS的实现 

1.我们可以用原生的JS封装一个事件绑定并具有事件委托功能的函数。如下:

function bindEvent(elem,type,selector,fn){
    //当只有三个参数时我们一般第三个参数是fn,则没有事件委托机制,需要把fn赋值为第三个参数
    if(!fn){
        fn = selector;
        selector = null;
    }
    elem.addEventListener(type,function(ev){
        if(selector){
            //如果使用了事件委托,需要匹配到目标元素
            let target = ev.target;
            if(target.matches(selector)){
                fn.call(target,ev);
            }
        }else{
            //普通绑定事件直接调用fn
            fn(ev);
        }
    })
}

target 和currentTarget的区别:

  • target在事件流的目标阶段,一个触发事件的对象的引用。
  • currentTarget当事件遍历DOM时,标识事件的当前目标。它总是引用事件处理程序附加到的元素,而不是event.target,它标识事件发生的元素。

只有当事件流处于目标阶段的时候,他们两个的指向才是一致的,而处于捕获和冒泡阶段的时候,target指向被单击的对象,而currentTarget指向当前事件活动的对象(注册该事件的对象,一般为父级),简单来说:currentTarget指的是事件触发后,冒泡到绑定处理程序的元素,就是绑定事件处理程序的元素,target指的是触发事件的元素。

 

另外,我们在获取目标元素的时候用到了Element.matches方法

语法:

let result = element.matches(selectorString);
  • result值为true或者false
  • selectorString是个css选择器

2.当然也可以用target.nodeName.toLowerCase() === 'button'来进行获取目标触发元素,以下作为例子结构:


    
    

当事件没有冒泡到目标元素的时候就一直循环到找到目标节点,否则什么也不做。

这里我们对比上面原生JS实现事件委托的两种方式的区别,除了匹配元素使用的 matches 方法不一样,我们第二种方式还用到了 while 循环去寻找目标对象,对于匹配使用的无论是 nodeName 还是 matches 并没有多大区别只是匹配目标元素(IE不支持matches 方法)。

事件委托用不用 while 循环去寻找取决于你的 html 结构,如果你的目标元素就是最底层(即点击的时候就是 ev.target 指向的元素)那么就不需要使用 while 循环查找。例如以下结构你的目标元素是 li,li 里面不再有元素节点。

  • 我是li1
  • 我是li2
  • 我是li3

另一种,如果你的目标元素中还有元素节点,但是你的目标仍然是 li,这个时候就需要使用 while + parentNode 去查找目标节点:

  • 我是li1
  • 我是li2
  • 我是li3

 

你可能感兴趣的:(基础知识,javascript,JS事件冒泡,JS事件委托,JS事件代理)