js中的事件委托(事件代理)

372 阅读3分钟

1、事件流

      事件流描述的是从页面接收到事件的顺序,包括三个阶段:事件捕获阶段、处于目标阶段和事件冒泡阶段。最先发生的是事件捕获,然后是具体的实际目标收到事件,最后才是冒泡阶段,可以在这个阶段对事件做出响应。

2、添加事件监听

(1)给元素添加事件监听的方法,可以直接在html上添加或者在JavaScript中指定的事件处理程序,但是需要注意,这种以‘on’开头的事件属于‘DOM0’级事件,重复定义时会覆盖掉原事件,而使用addEventListener,则不会覆盖之前添加的。

<input id='btn' value='click me' onclick='alert(this.value)'>

(2)使用addEventListener/removeEventListener方法,所有dom节点都包含这方法,传入三个参数:事件名、处理事件的函数、标示在捕获还是在冒泡阶段调用回调函数的布尔值。

addEventListener添加的事件处理函数只能用removeEventListener方法移除,传入 参数与addEventListener相同,意味着addEventListener添加的匿名函数无法移除,所以在用addEventListener添加处理函数时不能使用匿名函数。环境不支持addEventListener的时候,可以使用attachEvent/detachEvent。

let btn = document.getElementById('btn')
let handler = function () {alert(this.id)}
btn.addEventListener('click', handler,false)
btn.removeEventListener('click', handler,false)

3、事件委托

      在父元素上添加可以处理子元素事件的事件处理函数。

利用了事件冒泡,指定一个事件处理函数,来处理同一个类型的多个事件。

target是触发事件的最具体的元素,currenttarget是绑定事件的元素(在函数中一般等于this)。

<div id="outter">
   <div id="inner"></div>
</div>

var outter = document.querySelector('#outter')
outter.addEventListener('click',function(e){
    console.log(e.target.id)  //inner
    console.log(e.currentTarget.id)  //outter
    console.log(this === e.currentTarget)  //true
},false)

      当我们需要对很多元素添加事件的时候,可以通过将事件添加到它们的父节点而将事件委托给父节点来触发处理函数。

       这主要得益于浏览器的事件冒泡机制。

优点:

(1)管理的函数变少了,不需要为每个元素都添加监听函数,对于同一个父节点下面类似的子元素,可以通过委托给父元素的监听函数来处理事件。

(2)可以方便地动态添加和修改元素,不需要因为元素的改动而修改事件绑定。

(3)JavaScript和DOM节点之间的关联变少了。这样也就减少了因循环引用而带来的内存泄漏发生的概率。


获取目标元素:

function getEventTarget(e) {
    //event属性兼容写法
    e = e || window.event;
    //获取目标元素兼容写法
    return e.target || e.srcElement;
}

处理函数:

function editCell(e) {
    var target = getEventTarget(e);
    if(target.tagName.toLowerCase() == 'td') {
         // DO SOMETHING WITH THE CELL
    }
}

例子:

var oUl=document.getElementById("parent-list");
var aLi=oUl.getElementsByTagName('li');

function target(e) {
    var oEvent=e||event;
    return oEvent.target||oEvent.srcElement;
}

oUl.addEventListener('click',function (e) {
    var oEvent=e||event;
    var targets=target(oEvent);
    if (targets.tagName.toLowerCase()=='li') {
        console.log(targets.id);
    }
})

注:为父节点添加一个click事件,当子节点被点击的时候,click事件会从子节点开始向上冒泡。父节点捕获到事件之后,通过判断e.target.nodeName来判断是否为我们需要处理的节点。并且通过e.tartget拿到了被点击的LI节点。从而可以获取到相应的信息,并作处理。

jQuery中的delegate函数:

$("#link-list").delegate("a", "click", function(){
  // "$(this)" is the node that was clicked
  console.log("you clicked a link!",$(this));
});

注:jQuery的delegate的方法需要三个函数,一个选择器,一个事件名称,和事件处理函数。