JavaScript事件委托机制与this的比较

很多时候我们在完成交互时,页面的一些dom结构是根据后台传输过来的数据动态加载的,如果说我们需要给这些数量比较大的dom结构(比如说表格,或则ul>li)添加click或则hover事件时,手写/遍历生成元素内的onclick函数式不可取的,会大量的消耗浏览器内存,降低程序的性能。所以,采用事件委托机制或this就来替代就显得很有必要了。

一.什么是事件委托机制

简单来说,就是借助event事件对象和事件触发的冒泡流程来完成事件委托机制。冒泡流程顾名思义,当你点击某个元素时,事件捕捉会从它的父级往上查找,一直到domcument为止。而event事件对象则是委托机制的重点所在,借助它,我们可以做到定点触发,指哪打哪。
举个例子:

<button id="addBtn">添加</button>
<ul id="owenUl">
    <li>111</li>
    <li>222</li>
    <li>333</li>
</ul>

我们想给ul中的不同的li的添加点击事件,普通写法如下:

var $li = $('#owenUl').children();
var len = $li.length;
for(var i =0; i<= len-1;i++){
   $($li[i]).on('click',function () { 
      alert(this.innerHTML)
   }) 
}

此思路想必大家都经历过:先获取父级元素的所有子元素,然后在遍历子元素时添加点击事件。它的缺点我不再多说。

下面是事件委托写法:

$('#owenUl').on('click',function(event){
    //获取event和target兼容ie的写法
    var ev = event || window.event;
  var target = ev.target || ev.srcElement;
  //获取点击节点的元素类型名
    if(target.nodeName.toLowerCase() == "li"){
      //此时的target就是<li>dom元素
      alert(target.innerHTML)
    }
})$('#addBtn').on('click',function () {
   var str = '<li>123456</li>';
   $('#owenUl').append(str);
})

对于已存在的dom结构事件委托可以正常添加事件,那么对于用户操作后增加的dom呢?答案是也可以。
这里写图片描述

二.事件委托与this的比较

关于javascript的this,在什么情况下指向什么,严格模式和非严格模式的下this的区别在哪,还有this可以通过哪些函数改变指向,以及在箭头函数中this的指向等等这一系列问题,在本篇中暂不概述,有兴趣的话可以点击下面的链接看看我写的另一篇关于tihs指向问题的探究:
javascript this探究

我们在本篇中只谈谈用this改写的事件绑定与事件委托改写的事件绑定有何区别:
假如有以下dom结构:

<button id="addBtn">添加</button>
<ul id="owenUl">
    <li>111</li>
    <li>222</li>
    <li>333</li>
</ul>

我们进行以下改写:

$('#owenUl li').on('click', function () {
       alert(this.innerHTML);
 })

相比较,是不是比事件委托代码量还少?逻辑还简单?事件委托能起到的效果,它一样可以,在一些相对较复杂的业务需求下,它能使的代码复杂度更低:
假如我们有以下dom结构:

 <button id="addBtn">添加</button>
    <ul id="owenUl">
        <li>
            <span>1111</span>
        </li>
        <li>
            <span>2222</span>
        </li>
        <li>
            <span>3333</span>
        </li>
    </ul>

整个dom的css如下:

ul li {
        width: 49px;
        height: 30px;
        border: 1px solid gray;
        margin-bottom: 10px;
      }

实际效果如图:
这里写图片描述

现在我们有以下业务需求:
1.点击li里的区域时,要能显示span的内容。
2.点击不同的li显示各自span的内容。

如果是使用事件委托,我们可以这么写:

$('#owenUl').on('click', function (event) {
    //获取event和target兼容ie的写法
    var ev = event || window.event;
    var target = ev.target || ev.srcElement;
    var text;
    switch (target.nodeName.toLowerCase()) {
        case "li":
           var spanDom = target.children[0];
           text = spanDom.innerHTML;
           console.log('li')
           break;
        case "span":
           text = target.innerHTML;
           console.log('span')
           break;
        default:
           break;
        }
        console.log(text)
})

事件委托的机制的问题在于,当你在判断target.nodeName.toLowerCase() == 'li'的逻辑里去做业务时,你点击li中的span元素是得不到任务反应的,也就是说在此判断中,点击里面的span时,console.log('li')这一块的代码并不会被触发,因此代码的复杂度就高了。
  下面我们看用this来改写是什么样子:

$('#owenUl li').on('click', function (event) {
    var spanDom = this.children[0]
    console.log(spanDom.innerHTML);
})

很惊讶对吧,就两行代码。只要你在写代码前捋清了业务逻辑。用this改写代码的复杂度大大降低,也减少了维护成本。

综上,我个人是比较喜欢用this来进行事件绑定的。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章