您的位置:首页 > 其它

事件委托

2018-03-22 00:00 176 查看
为什么要用事件委托???事件委托有什么好处???
一般来说,dom是需要有事件处理程序的,我们会直接给他事件处理程序就好了,那么如果是很多dom元素需要添加事件处理呢???比如 100个li,每个li 都有相同的click点击事件,可能我们会有for循环的方法,来遍历所有li,然后为每个li添加绑定事件。这么做毫无疑问的是对性能有很大的影响;
在js中,添加到页面上的事件处理程序的多少将直接关系到页面运行的整体性能,因为需要不断的与dom节点进行交互,访问dom次数越多,引起浏览器重绘与重排的次数也就越多,就会延长整个页面的交互就绪时间。这就是性能优化,减少dom操作的原因;
如果采用事件委托,就会将所有的操作放到js程序里面,与dom的操作就只交互一次,这样减少了dom交互次数,性能就会提升;事件委托原理:事件委托就是利用事件冒泡原理实现的!事件冒泡:就是事件从最深节点开始,然后逐步向上传播事件;例:页面上有一个节点树,div > ul  > li  >  a比如给最里面的a 加一个click 事件,那么事件就会一层一层的往外执行,执行顺序 a > li > ul > div,  有这样一个机制,当我们给最外层的div 添加点击事件,那么里面的ul , li  , a  做点击事件的时候,都会冒泡到最外层的div上,所以都会触发,这就是事件委托,委托他们父集代为执行事件;
业务需求:实现功能,点击td ,单元格变色;html结构[html] view plain copy<!-- 事件绑定 -->  
    <table id="myTable" border="1">  
        <tr>  
            <td>1</td>  
            <td>2</td>  
            <td>3</td>  
        </tr>  
    </table>  
[javascript] view plain copywindow.onload = function(){  
    var oTa = document.getElementById("myTable");  
    var aTd = oTa.getElementsByTagName('td');  
    for(var i=0;i<aTd.length;i++){  
        aTd[i].onclick = function(){  
            aTd[i].style.background = 'red';  
        }  
    }  
}  
上面的办法是最简单的办法,也是最笨的办法,我们看看执行了多少次dom操作,首先找到table 然后遍历td ,当点击td的时候,又要找一次目标的li的位置,才能执行最后的操作,每次点击都要找一次td
那我们用事件委托的方式怎么来写呢,??
[javascript] view plain copywindow.onload = function(){  
    var oTa= document.getElementById("myTable");  
    oTa.onclick = function(){         //点击 table、td均可以alert(123)  
       alert(123);    
    }}  
[javascript] view plain copy<pre></pre>  
<pre></pre>  
这里用父集做事件处理,当td被点击时,由于冒泡原理事件就会冒泡到table上,因此table上有点击事件,所以事件就会被触发;
当然单当点击table本身的时候也是会触发的;如果我们只想让td触发而不想让table触发,怎么办呢???
Event对象提供了一个属性叫做target,可以返回事件的目标节点,我们称之为事件源,也就是说,target就可以表示当前事件操作的dom,但可能不是真正操作的dom,存在兼容性问题:标准浏览器:event.target,IE浏览器:event.srcElement,此时只是获取了当前节点的位置,但并不知道节点名称,这里我们用nodeName来获取具体是什么标签名,这个返回值是一个大写的,判断时需要转换为小写;[javascript] view plain copywindow.onload = function(){  
  var oTa = document.getElementById("myTable");  
  oTa.onclick = function(e){  
    var e = e || window.event;                    //处理兼容性  
    var target = e.target || e.srcElement;     
    target.nodeName.toLowerCase() == 'td' ? alert('我点中了table') :(target.style.background = 'red');  //三元运算符进行判断  
  }  
}  
这样改一下,就只有td会触发事件啦,且每次只执行一次dom操作,如果td很多的话,将大大减小dom的操作;上面的例子是说td点击都是产生同样的效果,要是每个td被点击的效果都不一样,那么事件委托还有用吗,???[javascript] view plain copy<!-- 事件绑定 -->  
    <table id="myTable" border="1">  
        <tr>  
            <td id="add">增加</td>  
            <td id="delete">删除</td>  
            <td id="modfiy">修改</td>  
            <td id="select">查找</td>  
        </tr>  
    </table>  
非事件委托写法[javascript] view plain copywindow.onload = function(){  
            var Add = document.getElementById("add");  
            var Delete = document.getElementById("delete");  
            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('选择');  
            }  
              
        }  
4个按钮,点击每一个做不同的动作,,,那么至少需要4次dom操作;如果用事件委托,能进行优化吗?事件委托写法
[javascript] view plain copywindow.onload = function(){  
            var myTable = document.getElementById("myTable");  
            myTable.onclick = function (ev) {     
                var ev = ev || window.event;  
                var target = ev.target || ev.srcElement;  
                if(target.nodeName.toLocaleLowerCase() == 'table'){  
                    switch(target.id){  
                        case 'add' :  
                            alert('添加');  
                            break;  
                        case 'remove' :  
                            alert('删除');  
                            break;  
                        case 'move' :  
                            alert('移动');  
                            break;  
                        case 'select' :  
                            alert('选择');  
                            break;  
                    }  
                }  
            }  
              
        }  
用事件委托,只用一次dom操作,就能完成所有的效果,性能肯定比上面的好;
前面讲的都是document加载完成后现有的dom节点的操作;那么如果是新增的节点,新增的节点会有事件吗???也就是说,新来的一个员工,他能收到快递吗????看一下正常添加节点的方法:[javascript] view plain copy<input type="button" name="" id="btn" value="添加" />  
    <ul id="ul1">  
        <li>111</li>  
        <li>222</li>  
        <li>333</li>  
        <li>444</li>  
    </ul>  
用一般的方法,循环加给li加点击事件,你会发现新增的li没有事件!!!解决办法:一般情况下,我们会用一个函数把那个for循环包起来,然后再在点击事件里调用这个函数,这样也能实现目的,功能虽然实现了,但无疑又增加了dom操作,用事件委托的方式如何做呢???[javascript] view plain copy<script type="text/javascript">  
    window.onload = function(){  
        var ul1 = document.getElementById('ul1');  
        var li = document.getElementsByTagName('li');  
        var btn = document.getElementById('btn');  
        var num = 1;  
        // for(var i=0;i<li.length;i++){  
        //  li[i].onclick = function(){  
        //      alert(this.innerHTML);  
        //  }  
        //  num++;  
        // }  
        ul1.onclick = function(e){  
            var e = e || window.event;  
            var target = e.target || event.srcElement;  
            console.log(target.nodeName);  
            target.nodeName.toLowerCase() == 'li' ? alert(target.innerHTML) : alert("您点中了ul标签");  
        }  
  
        btn.onclick = function(){  
            var oLi = document.createElement('li');  
            oLi.innerHTML = 111*num;  
            ul1.appendChild(oLi);  
        }  
    }  
上面是用事件委托的方式,新添加的子元素也是有点击功能的;我们可以发现,当用事件委托的时候,根本不需要遍历元素的子节点,只需要给父级元素添加事件就好了,其他的代码都是在js里面执行的,这样可以大大减少dom操作,这就是我理解的事件委托的精髓;
jQuery事件委托:我直接上code了,jquery的操作是如此的简单,一个on全搞定!!![html] view plain copy<!-- 事件绑定 -->  
    <table id="myTable" border="1">  
        <tr>  
            <td>111</td>  
            <td>222</td>  
            <td>333</td>  
            <td>444</td>  
        </tr>  
    </table>  
[javascript] view plain copy<script src="http://libs.baidu.com/jquery/1.9.1/jquery.min.js"></script>  
<script type="text/javascript">  
    $(function(){         
        $("#myTable td").click(function(){    
            $(this).html();  //普通写法,如果有100个td元素,就要绑定100次事件,十分浪费性能  
        })  
          
  
          
        $("#myTable").click(function(e){    //这种点击方式怎么排除父元素????  
            console.log(e.target);  
            var $clicked = $(e.target);    //e.target 捕捉到触发的元素  
            console.log(e.target.nodeName);  //结果为大写,用toLowerCase()  转换为小写  
            e.target.nodeName.toLowerCase() == 'table' ? alert('我点中table了')  : $clicked.html();  //排除父元素的点击效果  
        })  
          
  
        // jQuery1.7的on绑定方法,替代了以往的bind、live等方法,内部自动含有事件委托机制  
        // $(selector).on(event,childSelector,data,function,map)   on方法的语法  
        // $(selector).on(event,childSelector,function(){})        on方法语法,绑定在父元素上 事件,子选择器,回调函数  
        $("#myTable").on('click','td',function(){  
            $(this).html();  
        })  
    })  
</script>  
总结:
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: