js中的事件委托

事件委托:

  对'事件处理程序过多'问题的解决方案就是事件委托

  事件委托利用了事件冒泡,只指定一个事件处理程序,就可以管理某一类型的所有事件

  举个例子:页面上有这么一个节点树,div>ul>li>a;比如给最里面的a加一个click点击事件,那么这个事件就会一层一层的往外执      行,执行顺序a>li>ul>div,有这样一个机制,那么我们给最外面的div加点击事件,那么里面的ul,li,a做点击事件的时候,都会冒泡到最外层的div上,所以都会触发,这就是事件委托,委托它们父级代为执行事件。

举个例子:

子节点实现相同的功能:

<ul class="ul">

<li class="li">1</li>

<li class="li">2</li>

<li class="li">3</li>

<li class="li">4</li>

</ul>

实现功能是点击li,弹出1:

      var oUl = document.getElementsByClassName('ul');
      var oLi = document.getElementsByClassName('li');
      for(var i = 0; i< oLi.length;i++){
          oLi[i].onclick = function(){
              alert(1);
        }
      }

      var oUl = document.getElementsByClassName('ul')[0];
      oUl.onclick=function(){
          alert(1)
      }

 上面的代码的意思很简单,相信很多人都是这么实现的,我们看有多少次的dom操作,首先要找到ul,然后遍历li,然后点击li的时候,又要找一次目标的li的位置,才能执行最后的操作,每次点击都要找一次li;

那么我们用事件委托的方式做又会怎么样呢?

     var oUl = document.getElementsByClassName('ul')[0];
     oUl.onclick=function(){
          alert(1)
     }

这里用父级ul做事件处理,当li被点击时,由于冒泡原理,事件就会冒泡到ul上,因为ul上有点击事件,所以事件就会触发,当然,这里当点击ul的时候,也是会触发的,那么问题就来了,如果我想让事件代理的效果跟直接给节点的事件效果一样怎么办,比如说只有点击li才会触发?

Event对象提供了一个属性叫target,可以返回事件的目标节点,我们成为事件源,也就是说,target就可以表示为当前的事件操作的dom,但是不是真正操作dom,当然,这个是有兼容性的,标准浏览器用ev.target,IE浏览器用event.srcElement,此时只是获取了当前节点的位置,并不知道是什么节点名称,这里我们用nodeName来获取具体是什么标签名

var oUl = document.getElementsByClassName('ul')[0];
        oUl.onclick=function(event){
            var event = event||window.event;
            var target = event.target || event.srcElement;
            if(target.nodeName=='LI'){
                alert(1);
                alert(target.innerHTML)
            }
        }

这样改下就只有点击li会触发事件了,且每次只执行一次dom操作,如果li数量很多的话,将大大减少dom的操作

上面的例子是说li操作的是同样的效果,要是每个li被点击的效果都不一样,那么用事件委托还有用吗?

    <div id="box">
        <input type="button" id="add" value="添加" />
        <input type="button" id="remove" value="删除" />
        <input type="button" id="move" value="移动" />
        <input type="button" id="select" value="选择" />
    </div>
var oBox = document.getElementById('box');
        var add = document.getElementById('add');
        var remove = document.getElementById('remove');
        var move = document.getElementById('move');
        var select = document.getElementById('select');
        add.onclick = function(){
            alert('添加');
        }
        remove.onclick = function(){
            alert('删除');
        }
        move.onclick = function(){
            alert('移动');
        }
        select.onclick = function(){
            alert('选择');
        }

优化后

var oBox = document.getElementById('box');
        oBox.onclick = function(){
            var event = event||window.event;
            var target = event.target || event.srcElement;
            if(target.nodeName == 'INPUT'){
                switch(target.id){
                    case 'add':
                        alert('添加');
                        break;
                    case 'remove':
                        alert('删除');
                        break;
                    case 'move':
                        alert('移动');
                        break;
                    case 'select':
                        alert('选择');
                        break;
                }
            }
        }

现在讲的都是document加载完成的现有dom节点下的操作,那么如果是新增的节点,新增的节点会有事件吗?

现在是移入li,li变红,移出li,li变白,这么一个效果,然后点击按钮,可以向ul中添加一个li子节点

        <input type="button" name="" id="btn" value="添加" />
        <ul id="ul">
            <li>111</li>
            <li>222</li>
            <li>333</li>
            <li>444</li>
        </ul>

一般的做法

var oBtn = document.getElementById("btn");
            var oUl = document.getElementById("ul1");
            var aLi = oUl.getElementsByTagName('li');
            var num = 4;
            for(var i = 0;i<aLi.length;i++){
                aLi[i].onmouseover = function(){
                    this.style.background = 'red';
                }
                aLi[i].onmouseout = function(){
                    this.style.background = 'white';
                }
            }
            oBtn.onclick = function(){
                num++;
                var addLi = document.createElement('li');
                addLi.innerHTML = 111*num;
                oUl.appendChild(addLi)
            }

 但是你会发现,新增的li是没有事件的,说明添加子节点的时候,事件没有一起添加进去,这不是我们想要的结果,那怎么做呢?一般的解决方案会是这样,将for循环用一个函数包起来,在添加新街店的时候再调用它,这里就不演示了,但无疑又新加了一个dom操作

优化:

var oBtn = document.getElementById("btn");
            var oUl = document.getElementById("ul");
            var aLi = oUl.getElementsByTagName('li');
            var num =4;
            oUl.onmouseover = function(event){
                var event = event||window.event;
                var target = event.target||event.scrElement;
                if(target.nodeName == 'LI'){
                    target.style.background = 'red';
                }
            }
            oUl.onmouseout = function(event){
                var event = event||window.event;
                var target = event.target||event.scrElement;
                if(target.nodeName == 'LI'){
                    target.style.background = 'white';
                }
            }
            oBtn.onclick = function(){
                num++;
                var addLi = document.createElement('li');
                addLi.innerHTML = 111*num;
                oUl.appendChild(addLi)
            }

上面是用事件委托的方式,新添加的子元素是带有事件效果的,我们可以发现,当用事件委托的时候,根本就不需要去遍历元素的子节点,只需要给父级元素添加事件就好了,其他的都是在js里面的执行,这样可以大大的减少dom操作,这才是事件委托的精髓所在。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值