JS(原生)事件委托:为动态创建的节点绑定事件
项目开发中经常需要为动态创建的节点绑定事件,
比如需要创建一个动态列表:在li的数量非常少的时候,为每一个li绑定事件不会存在太多性能方面的问题,但是当列表非常的长,长到上百上千甚至上万的时候(假设),为每个li绑定事件就会对页面性能产生很大的影响。当有大量元素需要绑定相同事件的时候可采用事件委托,将在目标元素上要处理的事件委托给父元素或者祖先元素
优点
事件委托对于web应用程序的性能有如下几个优点:
1.需要管理的函数变少了
2.占用的内存少了
3.javascript代码和Dom结构之间的关联更少了
首先动态创建节点:
点击按钮 创建一个li节点并将文本框中输入的值做为此节点的内容,新创建的LI节点插入到最前面
HTML代码:
1 <body> 2 <input id="txt1" type="text"/> 3 <input id="btn1" type="button" value="创建li"/> 4 <ul id="ul1"> 5 </ul> 6 7 <script> 8 window.onload = function(){ 9 var oul = document.getElementById("ul1"); 10 var obtn = document.getElementById("btn1"); 11 var otxt = document.getElementById("txt1"); 12 13 /************************添加节点**********************************/ 14 obtn.onclick = function(){ 15 var oli = document.createElement(‘li‘); 16 oli.innerHTML = otxt.value + ‘ <a class="ac" href="javascript:;">删除</a>‘; 17 ali = oul.getElementsByTagName("li"); 18 19 //1:追加元素 20 //oul.appendChild(oli); 21 22 //2:插入元素到前面 23 //oul.insertBefore(oli,ali[0]); 若不存在元素ali[0]在IE中会报错 所以需要兼容 24 if( ali.length > 0 ) 25 { 26 oul.insertBefore(oli, ali[0]); 27 } 28 else 29 { 30 oul.appendChild(oli); 31 } 32 } 33 34 } 35 36 </script>
其次为LI中的A元素绑定点击事件:点击A元素删除所在的LI节点
采用事件委托,有如下两种方法供大家参考:
方法一:传统绑定 [直接给元素绑定事件]
1 <body> 2 <input id="txt1" type="text"/> 3 <input id="btn1" type="button" value="创建li"/> 4 <ul id="ul1"> 5 </ul> 6 7 <script> 8 window.onload = function(){ 9 var oul = document.getElementById("ul1"); 10 var obtn = document.getElementById("btn1"); 11 var otxt = document.getElementById("txt1"); 12 13 /************************添加节点**********************************/ 14 obtn.onclick = function(){ 15 var oli = document.createElement(‘li‘); 16 oli.innerHTML = otxt.value + ‘ <a class="ac" href="javascript:;">删除</a>‘; 17 ali = oul.getElementsByTagName("li"); 18 19 if( ali.length > 0 ) 20 { 21 oul.insertBefore(oli, ali[0]); 22 } 23 else 24 { 25 oul.appendChild(oli); 26 } 27 } 28 29 /************************绑定事件**********************************/ 30 oul.onclick = function( e ) { 31 e = e || window.event; 32 var t = e.target || e.srcElement; //t:目标对象 33 var tagName = t.tagName; //tagName标签名称 34 if( tagName == ‘A‘ ) { 35 this.removeChild(t.parentNode); //删除元素 this指oul 36 } 37 } 38 39 } 40 41 </script>
方法1: a、优点:
1、简单可靠,确保在不同的浏览器中保持一致;
2、处理事件时,this关键字引用的是当前的元素;
b、缺点:
1、只支持冒泡阶段的运行;
2、一个元素一次只能绑定一个事件处理函数,同类事件处理函数会相互覆盖;[如给同一元素绑定两次.onclick事件,则只有最后一个绑定成功]
方式二:事件监听
在IE6-8下可用attachEvent,在IE9,谷歌和火狐下则要用addEventListener
若为同一元素多次绑定,则会产生追加的效果,事件触发是的执行顺序,由下至上
attachEvent()有两个参数
第一个是事件名称
第二个是需执行的函数;
addEventListener()有三个参数
第一个是事件名称,但与IE事件不同的是,事件不带"on",比如"onsubmit"在这里应为"submit"
第二个是需执行的函数
第三个参数为布尔值,表示该事件的响应顺序(useCapture),userCapture若为true,则浏览器采用Capture[捕获], 若为false则采用bubbing[冒泡]方式。
对函数进行封装后兼容各大主流浏览器的监听事件如下:
1 /* 2 * oTarget:监听对象 3 * sEventType:监听事件类型,如click,mouseover 4 * fnHandler:监听函数 5 */ 6 function addEventHandler(oTarget, sEventType, fnHandler) { 7 if (oTarget.addEventListener) { //监听IE9,谷歌和火狐 8 oTarget.addEventListener(sEventType, fnHandler, false); 9 } else if (oTarget.attachEvent) { //IE 10 oTarget.attachEvent("on" + sEventType, fnHandler); 11 } else { 12 oTarget["on" + sEventType] = fnHandler; 13 } 14 }
HTML代码:
1 <body> 2 <input id="txt1" type="text"/> 3 <input id="btn1" type="button" value="创建li"/> 4 <ul id="ul1"> 5 </ul> 6 7 <script> 8 9 window.onload = function(){ 10 var oul = document.getElementById("ul1"); 11 var obtn = document.getElementById("btn1"); 12 var otxt = document.getElementById("txt1"); 13 14 /************************添加节点**********************************/ 15 obtn.onclick = function(){ 16 var oli = document.createElement(‘li‘); 17 oli.innerHTML = otxt.value + ‘ <a class="ac" href="javascript:;">删除</a>‘; 18 ali = oul.getElementsByTagName("li"); 19 20 if( ali.length > 0 ) 21 { 22 oul.insertBefore(oli, ali[0]); 23 } 24 else 25 { 26 oul.appendChild(oli); 27 } 28 29 } 30 31 /************************绑定事件**********************************/ 32 function fnHandle(e) 33 { 34 e = e || window.event; //IE window.event 35 var t = e.target || e.srcElement; //目标对象 36 var classname = t.className; 37 if( classname == ‘ac‘ ) 38 { 39 oul.removeChild(t.parentNode); 40 } 41 } 42 43 addEventHandler(oul, ‘click‘, fnHandle); 44 45 } 46 47 /* 48 * oTarget:监听对象 49 * sEventType:监听事件类型,如click,mouseover 50 * fnHandler:监听函数 51 */ 52 function addEventHandler(oTarget, sEventType, fnHandler) { 53 if (oTarget.addEventListener) { //监听IE9,谷歌和火狐 54 oTarget.addEventListener(sEventType, fnHandler, false); 55 } else if (oTarget.attachEvent) { //IE 56 oTarget.attachEvent("on" + sEventType, fnHandler); 57 } else { 58 oTarget["on" + sEventType] = fnHandler; 59 } 60 } 61 62 </script>
既然讲到了采用事件监听给对象绑定方法,那也顺便说说解除相应的绑定
在IE6-8下可用detachEvent,在IE9,谷歌和火狐下则要用removeEventListener
对函数进行封装后兼容各大主流浏览器的解除事件监听方法如下:
1 /* 2 * 采用事件监听给对象绑定方法后,可以解除相应的绑定 3 * oTarget:监听对象 4 * sEventType:监听事件类型,如click,mouseover 5 * fnHandler:监听函数 6 */ 7 function removeEventHandler(oTarget, sEventType, fnHandler) { 8 if (oTarget.removeEventListener){ 9 //监听IE9,谷歌和火狐 10 oTarget.removeEventListener(sEventType, fnHandler, false); 11 } else if (oTarget.detachEvent){ 12 oTarget.detachEvent("on" + sEventType, fnHandler); 13 }else { 14 delete oTarget["on" + sEventType]; 15 } 16 }
HTML代码:
1 <input id="txt1" type="text"/> 2 <input id="btn1" type="button" value="创建li"/> 3 <ul id="ul1"> 4 </ul> 5 6 <script> 7 8 window.onload = function(){ 9 var oul = document.getElementById("ul1"); 10 var obtn = document.getElementById("btn1"); 11 var otxt = document.getElementById("txt1"); 12 13 /************************添加节点**********************************/ 14 obtn.onclick = function(){ 15 var oli = document.createElement(‘li‘); 16 oli.innerHTML = otxt.value + ‘ <a class="ac" href="javascript:;">删除</a>‘; 17 ali = oul.getElementsByTagName("li"); 18 19 if( ali.length > 0 ) 20 { 21 oul.insertBefore(oli, ali[0]); 22 } 23 else 24 { 25 oul.appendChild(oli); 26 } 27 28 } 29 30 /************************绑定事件**********************************/ 31 function fnHandle(e) 32 { 33 e = e || window.event; //IE window.event 34 var t = e.target || e.srcElement; //目标对象 35 var classname = t.className; 36 if( classname == ‘ac‘ ) 37 { 38 oul.removeChild(t.parentNode); 39 } 40 } 41 42 //事件绑定 43 addEventHandler(oul, ‘click‘, fnHandle); 44 //解除绑定 45 removeEventHandler(oul,‘click‘,fnHandle); 46 47 } 48 49 /* 50 * oTarget:监听对象 51 * sEventType:监听事件类型,如click,mouseover 52 * fnHandler:监听函数 53 */ 54 function addEventHandler(oTarget, sEventType, fnHandler) { 55 if (oTarget.addEventListener) { //监听IE9,谷歌和火狐 56 oTarget.addEventListener(sEventType, fnHandler, false); 57 } else if (oTarget.attachEvent) { //IE 58 oTarget.attachEvent("on" + sEventType, fnHandler); 59 } else { 60 oTarget["on" + sEventType] = fnHandler; 61 } 62 } 63 64 /* 65 * 采用事件监听给对象绑定方法后,可以解除相应的绑定 66 * oTarget:监听对象 67 * sEventType:监听事件类型,如click,mouseover 68 * fnHandler:监听函数 69 */ 70 function removeEventHandler(oTarget, sEventType, fnHandler) { 71 if (oTarget.removeEventListener){ 72 //监听IE9,谷歌和火狐 73 oTarget.removeEventListener(sEventType, fnHandler, false); 74 } else if (oTarget.detachEvent){ 75 oTarget.detachEvent("on" + sEventType, fnHandler); 76 }else { 77 delete oTarget["on" + sEventType]; 78 } 79 } 80 81 </script>
注:解除绑定事件的时候一定要用函数的句柄,把整个函数写上是无法解除绑定的
1 //正确写法 2 removeEventHandler(oul,‘click‘,fnHandle); 3 4 //错误写法 5 removeEventHandler(oul,‘click‘,function(e) 6 { 7 e = e || window.event; //IE window.event 8 var t = e.target || e.srcElement; //目标对象 9 var classname = t.className; 10 if( classname == ‘ac‘ ) 11 { 12 oul.removeChild(t.parentNode); 13 } 14 });
方法一解除绑定:oul.onclick = null;
总结:
方法一和方法二的区别:
当同一个对象使用.onclick的写法触发多个方法的时候,后一个方法会把前一个方法覆盖掉,也就是说,在对象的onclick事件发生时,只会执行最后绑定的方法。
而用事件监听则不会有覆盖的现象,每个绑定的事件都会被执行,也便于解除事件绑定