addEventListener,jq.on以及事件委托
⼤概的意思就是,原⽣的addEventListener⽐jq的on慢了60倍,两者分别执⾏10^5次, jq⽤了762毫秒, 原⽣⽤了45165毫秒。知乎下⾯的回答并不是很详细,但是提到了⼀个概念,事件委托。于是打算把这个知识点啃⼀下。
addEventListener vs onclick:
机构海外留学说是⽐较这两个,其实是⽐较三个:addEventListener, attachEvent, onClick;
1) IE 8 以及更低版本的 IE 中,需要⽤⽅法:
element.attachEvent('onclick', function() { /* do stuff here*/ });
2)对于 IE 9 和更⾼版本的 IE,以及其它浏览器,则要⽤⽅法:
element.addEventListener('click', function() { /* do stuff here*/ }, fal);
⽤上⾯这种⽅法(),理论上可以为⼀个元素绑定⽆数个事件,实际应⽤中则决定于客户端的电脑内存以及浏览器。
上⾯的例⼦应⽤了这个特性,还可以使⽤或者来添加事件监听器:
var myFunctionReference = function() { /* do stuff here*/ }
element.attachEvent('onclick', myFunctionReference);
element.addEventListener('click', myFunctionReference , fal);
出师表 翻译另⼀个重要特性,则是上⾯这段代码中最后⼀⾏的最后⼀个参数,⽤来控制监听器。95%的使⽤场景中,这个参数都
side by side为fal,addEventListener 以及内联事件则都没有可以实现相同功能的这个参数。
onclick:
(HTML 的 onclick="" 属性,以及 lick)
shutout在所有⽀持 JavaScript 的浏览器中,可以⽤下⾯的⽅式来添加内联的事件监听器。
史瓦济兰
<a id="testing" href="#" onclick="alert('did stuff inline');">Click me</a>
虽然很多有经验的开发⼈员对这种⽅式嗤之以⿐,但是它的确⾜够的简单粗暴。在这⾥你不能使⽤闭包或者匿名函数,并且控制域也是有限的。
还有另⼀种⽅法:
这个⽅法能实现相同的效果,并且有更多的控制域(因为是 JS 脚本,⽽不是 HTML 代码),当然了,也能使⽤匿名函数、构造函数、闭包。
内联事件⼀个明显的不⾜:由于内联事件是的,这些属性可以被覆盖,所以如果为同⼀个事件绑定了多个处理程序,那么最后⼀个处理程序会覆盖之前的程序。
var element = ElementById('testing');
运⾏上⾯的⽰例,将只会看到“did stuff #2”——第⼆⾏代码覆盖了默认的内联 onclick 属性,第三⾏代码⼜将第⼆⾏代码覆盖了,所以会产⽣这样的结果。
简单总结:
低版本使⽤attachEvent,⾼版本⽤addEventListener,onclick是作为内联事件,也可以⽤不内联的⽅式,⽅便将事件写成各种形式。onclick因为有内联属性,它作为元素属性出现,因此⼀个事件绑定多个程序时,会被最后⼀个程序覆盖。⽽前两者则不会。且前两者还可以控制监听器对冒泡事件的响应。
asfd事件委托:
上⽂提到冒泡事件,委托就是利⽤冒泡事件来做的性能优化。
那什么叫事件委托呢?它还有⼀个名字叫事件代理,JavaScript⾼级程序设计上讲:事件委托就是利⽤事件冒泡,只指定⼀个事件处理程序,就可以管理某⼀类型的所有事件。那这是什么意思呢?⽹上的各位⼤⽜们讲事件委托基本上都⽤了同⼀个例⼦,就是取快递来解释这个现象,我仔细揣摩了⼀下,这个例⼦还真是恰当,我就不去想别的例⼦来解释了,借花献佛,我摘过来,⼤家认真领会⼀下
事件委托到底是⼀个什么原理:
有三个同事预计会在周⼀收到快递。为签收快递,有两种办法:⼀是三个⼈在公司门⼝等快递;⼆是委托给前台MM代为签收。现实当中,我们⼤都采⽤委托的⽅案(公司也不会容忍那么多员⼯站在门⼝就为了等快递)。前台MM收到快递后,她会判断收件⼈是谁,然后按照收件⼈的要求签收,甚⾄代为付款。这种⽅案还有⼀个优势,那就是即使公司⾥来了新员⼯(不管多少),前台MM也会在收到寄给新员⼯的快递后核实并代为签收。
这⾥其实还有2层意思的:
第⼀,现在委托前台的同事是可以代为签收的,即程序中的现有的dom节点是有事件的;
第⼆,新员⼯也是可以被前台MM代为签收的,即程序中新添加的dom节点也是有事件的。
为什么要⽤事件委托:
⼀般来说,dom需要有事件处理程序,我们都会直接给它设事件处理程序就好了,那如果是很多的dom需要添加事件处理呢?⽐如我们有100个li,每个li都有相同的click点击事件,可能我们会⽤for循环的⽅法,来遍历所有的li,然后给它们添加事件,那这么做会存在什么影响呢?
情人节快乐英语
在JavaScript中,添加到页⾯上的事件处理程序数量将直接关系到页⾯的整体运⾏性能,因为需要不断的与dom节点进⾏交互,访问dom 的次数越多,引起浏览器重绘与重排的次数也就越多,就会延长整个页⾯的交互就绪时间,这就是为什么性能优化的主要思想之⼀就是减少DOM操作的原因;如果要⽤事件委托,就会将所有的操作放到js程序⾥⾯,与dom的操作就只需要交互⼀次,这样就能⼤⼤的减少与dom 的交互次数,提⾼性能;
每个函数都是⼀个对象,是对象就会占⽤内存,对象越多,内存占⽤率就越⼤,⾃然性能就越差了(内存不够⽤,是硬伤,哈哈),⽐如上⾯的100个li,就要占⽤100个内存空间,如果是1000个,10000个呢,那只能说呵呵了,如果⽤事件委托,那么我们就可以只对它的⽗级(如果只有⼀个⽗级)这⼀个对象进⾏操作,这样我们就需要⼀个内存空间就够了,是不是省了很多,⾃然性能就会更好。
事件委托的原理:
事件委托是利⽤事件的冒泡原理来实现的,何为事件冒泡呢?就是事件从最深的节点开始,然后逐步向上传播事件,举个例⼦:页⾯上有这么⼀个节点树,div>ul>li>a;⽐如给最⾥⾯的a加⼀个click点击事件,那么这个事件就会⼀层⼀层的往外执⾏,执⾏顺序a>li>ul>div,有这样⼀个机制,那么我们给最外⾯的div加点击事件,那么⾥⾯的ul,li,a做点击事件的时候,都会冒泡到最外层的div上,所以都会触发,这就是事件委托,委托它们⽗级代为执⾏事件。
事件委托怎么实现:
终于到了本⽂的核⼼部分了,哈哈,在介绍事件委托的⽅法之前,我们先来看⼀段⼀般⽅法的例⼦:
⼦节点实现相同的功能:
<ul id="ul1">
<li>111</li>
<li>222</li>
<li>333</li>
<li>444</li>
</ul>
实现功能是点击li,弹出123:
var oUl = ElementById("ul1");
var aLi = ElementsByTagName('li');
for(var i=0;i<aLi.length;i++){
aLi[i].onclick = function(){
alert(123);非主流情侣网名
}
}
}
上⾯的代码的意思很简单,相信很多⼈都是这么实现的,我们看看有多少次的dom操作,⾸先要找到ul,然后遍历li,然后点击li的时候,⼜要找⼀次⽬标的li的位置,才能执⾏最后的操作,每次点击都要找⼀次li;
那么我们⽤事件委托的⽅式做⼜会怎么样呢?
var oUl = ElementById("ul1");
alert(123);
}
}
这⾥⽤⽗级ul做事件处理,当li被点击时,由于冒泡原理,事件就会冒泡到ul上,因为ul上有点击事件,所以事件就会触发,当然,这⾥当点击ul的时候,也是会触发的,那么问题就来了,如果我想让事件代理的效果跟直接给节点的事件效果⼀样怎么办,⽐如说只有点击li才会触发,不怕,我们有绝招:
Event对象提供了⼀个属性叫target,可以返回事件的⽬标节点,我们成为事件源,也就是说,target就可以表⽰为当前的事件操作的dom,但是不是真正操作dom,当然,这个是有兼容性的,标准浏览器⽤ev.target,IE浏览器⽤event.srcElement,此时只是获取了当前节点的位置,并不知道是什么节点
名称,这⾥我们⽤nodeName来获取具体是什么标签名,这个返回的是⼀个⼤写的,我们需要转成⼩写再做⽐较(习惯问题):
var oUl = ElementById("ul1");
lick = function(ev){
var ev = ev || window.event;
var target = ev.target || ev.srcElement;
LowerCa() == 'li'){
alert(123);
alert(target.innerHTML);
}
}kirkland
}
这样改下就只有点击li会触发事件了,且每次只执⾏⼀次dom操作,如果li数量很多的话,将⼤⼤减少dom的操作,优化的性能可想⽽知!
上⾯的例⼦是说li操作的是同样的效果,要是每个li被点击的效果都不⼀样,那么⽤事件委托还有⽤吗?
<div id="box">
<input type="button" id="add" value="添加"/>
<input type="button" id="remove" value="删除"/>
d的笔顺怎么写
<input type="button" id="move" value="移动"/>
<input type="button" id="lect" value="选择"/>
</div>
var Add = ElementById("add");
var Remove = ElementById("remove");
var Move = ElementById("move");
var Select = ElementById("lect");
alert('添加');
};
alert('删除');
};
alert('移动');
};
alert('选择');
}
}
上⾯实现的效果我就不多说了,很简单,4个按钮,点击每⼀个做不同的操作,那么⾄少需要4次dom操作,如果⽤事件委托,能进⾏优化吗?
var oBox = ElementById("box");
var ev = ev || window.event;
var target = ev.target || ev.srcElement;
LocaleLowerCa() == 'input'){
switch(target.id){
ca 'add' :
alert('添加');
break;
ca 'remove' :
alert('删除');
break;
ca 'move' :
alert('移动');
break;
ca 'lect' :
alert('选择');
break;
}
}
}
}
⽤事件委托就可以只⽤⼀次dom操作就能完成所有的效果,⽐上⾯的性能肯定是要好⼀些的
现在讲的都是document加载完成的现有dom节点下的操作,那么如果是新增的节点,新增的节点会有事件吗?也就是说,⼀个新员⼯来了,他能收到快递吗?
看⼀下正常的添加节点的⽅法:
<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变红,移出li,li变⽩,这么⼀个效果,然后点击按钮,可以向ul中添加⼀个li⼦节点