什么是事宜
javascript与HTML之间交互就是经由过程事宜完成的,事宜就是文档或阅读器窗口中发作的一些特定的交互霎时。事宜在阅读器中是以对象的情势存在的,即event,触发一个事宜,就会发生一个事宜对象event,该对象包含着一切与事宜有关的信息,包含致使事宜的元素、事宜的范例以及其他与特定事宜相干的信息。
DOM元素增加事宜
1.DOM元素事宜属性
<button onclick="clickFun()">addEvent</button>
2.javascript剧本增加事宜
a. element.onclick=function(e){}
b. element.addEventListener(event,function(e),useCapture)
- 适用范围:当代阅读器(IE9+, Firefox , chorme, safari, opera)
- 参数引见:event必需,事宜称号。(注:不含“on”,比方“click”、“mouseover”等)。function必需,指定事宜触发时实行的函数。useCapture可选,布尔值,指定事宜是不是在捕捉或冒泡阶段实行,默许false(冒泡)。
c. element.attachEvent(event,function(e))
- 适用范围:IE 6、7、8
- 参数引见:event 必需,字符串,事宜称号。(注:含“on”,比方“onclick”、“onmouseover”等)。function必需,指定事宜触发时实行的函数。
<button id="myBtn">点击这里</button>
<script>
document.getElementById("myBtn").onclick=function(){clickFun()};
document.getElementById("myBtn").addEventListener("click",function(event){
clickFun();
},false); //采纳事宜冒泡体式格局给dom元素注册click事宜
document.getElementById("myBtn").addEventListener("click",function(event){
clickFun();
},true); //采纳事宜捕捉体式格局给dom元素注册click事宜
document.getElementById("myBtn").attachEvent("click",function(event){
clickFun();
});
</script>
扩大:原生Javascript写法,跨阅读器增加事宜
var EventUtil = {
// 增加事宜监听
add: function(element, type, callback){
if(element.addEventListener){
element.addEventListener(type, callback, false);
} else if(element.attachEvent){
element.attachEvent('on' + type, callback);
} else {
element['on' + type] = callback;
}
}
// 移除事宜监听
remove: function(element, type, callback){
if(element.removeEventListener){
element.removeEventListener(type, callback, false);
} else if(element.detachEvent){
element.detachEvent('on' + type, callback);
} else {
element['on' + type] = null;
}
}
}
<button id="myBtn">点击这里</button>
<script>
var myBtn = document.getElementById("myBtn");
EventUtil.add(myBtn, 'click', function(){
console.log('被点击了');
});
事宜捕捉、事宜冒泡
事宜捕捉
事宜捕捉(event capturing):当鼠标点击或许触发dom事宜时,阅读器会从根节点最先由外到内举行事宜流传,即点击了子元素,假如父元素经由过程事宜捕捉体式格局注册了对应的事宜的话,会先触发父元素绑定的事宜。
事宜冒泡
事宜冒泡(dubbed bubbling):与事宜捕捉恰恰相反,事宜冒泡递次是由内到外举行事宜流传,直到根节点。
注:无论是事宜捕捉照样事宜冒泡,它们都有一个配合的行动,就是事宜流传
阻挠事宜捕捉/事宜冒泡
event.stopPropagation()
event.stopImmediatePropagation()
- event.stopPropagation()
会阻挠事宜继承分发到其他document节点,然则当前节点绑定的多个事宜会继承按注册的递次实行 - event.stopImmediatePropagation()
不仅阻挠事宜继承分发到其他document,还会将事宜分发当场住手,在当前事宜以后注册的其他事宜,都不会实行
举个栗子:此栗子是阻挠事宜捕捉,阻挠事宜冒泡道理一样
<div id="div1">
<button id="button1">测试</button>
</div>
<script type="application/javascript">
var div1 = document.getElementById("div1");
var btn = document.getElementById("button1");
div1.addEventListener("click", function () {
alert("div1第一次实行");
event.stopPropagation();
}, true);
div1.addEventListener("click", function () {
alert("div1第二次实行");
}, true);
btn.addEventListener("click", function (event) {
alert("button 实行");
}, true);
</script>
//实行结果 alert("div1第一次实行"); alert("div1第二次实行");
<div id="div1">
<button id="button1">测试</button>
</div>
<script type="application/javascript">
var div1 = document.getElementById("div1");
var btn = document.getElementById("button1");
div1.addEventListener("click", function () {
alert("div1第一次实行");
event.stopImmediatePropagation();
}, true);
div1.addEventListener("click", function () {
alert("div1第二次实行");
}, true);
btn.addEventListener("click", function (event) {
alert("button 实行");
}, true);
</script>
//实行结果 alert("div1第一次实行");
事宜代办
什么是事宜代办
事宜代办也能够称之为事宜托付,事宜代办就是在先人级DOM元素绑定一个事宜,当触发子孙级DOM元素的事宜时,应用事宜冒泡的道理来触发绑定在先人级DOM的事宜。
那这是什么意义呢?网上的列位大牛们讲事宜代办基本上都用了同一个例子,就是取快递来诠释这个征象,借花献佛,人人仔细体会一下事宜代办究竟是一个什么道理:
有三个同事估计会在周一收到快递。为签收快递,有两种要领:一是三个人在公司门口等快递;二是托付给前台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个呢,那只能呵呵了,假如用事宜代办,那末我们就可以够只对它的父级(假如只要一个父级)这一个对象举行操纵,如许我们就须要一个内存空间就够了,是不是是省了许多,天然机能就会更好。
事宜代办的完成
在引见事宜代办的要领之前,先来看一段平常要领的栗子:
<ul id="ulDelegate">
<li>111</li>
<li>222</li>
<li>333</li>
<li>444</li>
</ul>
<script>
window.onload = function(){
var ulDelegate= document.getElementById("ulDelegate");
var liDelegate= ulDelegate.getElementsByTagName('li');
for(var i=0;i<liDelegate.length;i++){
liDelegate[i].onclick = function(){
alert('noDelegate');
}
}
}
</script>
上面的代码很简单,我们看看有多少次的dom操纵,首先要找到ul,然后遍历li,然后点击li的时刻,又要找一次目的的li的位置,才实行末了的操纵,每次点击都要找一次li。
用事宜代办的体式格局来完成,上栗子:
window.onload = function(){
var ulDelegate= document.getElementById("ulDelegate");
ulDelegate.onclick = function(){
alert('Delegate');
}
}
这里用父级ul做事宜处置惩罚,当li被点击时,因为冒泡道理,事宜就会冒泡到ul上,因为ul上有点击事宜,所以事宜就会触发,固然,这里当点击ul的时刻,也是会触发的。
那末题目就来了,假如我想让事宜代办的结果跟直接给节点的事宜结果一样怎么办,比方说只要点击li才会触发,这时候,Event对象就派上用场了,Event供应了一个属性叫target,能够返回事宜的目的节点,我们称为事宜源,也就是说,target就可以够示意为当前的事宜操纵的dom,然则不是是真正操纵dom,这个是有兼容性的,规范阅读器用ev.target,IE阅读器用event.srcElement,此时只是猎取了当前节点的位置,并不知道是什么节点称号,这里我们用nodeName来猎取详细是什么标署名,这个返回的是一个大写的,我们能够转成小写再做比较,或许不转。
window.onload = function(){
var ulDelegate= document.getElementById("ulDelegate");
ulDelegate.onclick = function(ev){
var ev = ev || window.event;
var target = ev.target || ev.srcElement;
if(target.nodeName.toLowerCase() == 'li'){
alert('Delegate');
alert(target.innerHTML);
}
}
}
如许就只要点击li会触发事宜了,且每次只实行一次dom操纵,假如li数目许多的话,将大大削减dom的操纵,优化的机能可想而知!
上面的栗子是说li操纵的是一样的结果,假如每一个li被点击的结果都不一样,上栗子:
<ul id="ulDelegate">
<li id='add'>增加</li>
<li id='delete'>删除</li>
<li id='edit'>修正</li>
</ul>
<script>
window.onload = function(){
var ulDelegate= document.getElementById("ulDelegate");
ulDelegate.onclick = function (ev) {
var ev = ev || window.event;
var target = ev.target || ev.srcElement;
if(target.nodeName.toLocaleLowerCase() == 'li'){
switch(target.id){
case 'add' :
alert('增加');
break;
case 'delete' :
alert('删除');
break;
case 'edit' :
alert('挪动');
break;
}
}
}
}
</script>
再来末了一个事宜代办的栗子,当我们新增一个li元素的时刻,一样先看一下平常写法:
<ul id="ulDelegate">
<li>111</li>
<li>222</li>
<li>333</li>
<li>444</li>
</ul>
<button id="addLi">新增li</button>
<script>
var ulDelegate= document.getElementById("ulDelegate");
var liDelegate= ulDelegate.getElementsByTagName('li');
var addLi = document.getElementById("addLi");
function addClick() {
for(var i=0;i<liDelegate.length;i++){
liDelegate[i].onclick = function(){
alert('noDelegate');
}
}
}
addClick();
addLi.onclick = function(){
var addLiElement = document.createElement('li');
addLiElement .innerHTML = 10000*Math.random();
ulDelegate.appendChild(addLiElement );
addClick();
}
</script>
再来看一下事宜代办的写法:
window.onload = function(){
var ulDelegate = document.getElementById("ulDelegate");
var addLi = document.getElementById("addLi");
ulDelegate.onclick = function(ev){
var ev = ev || window.event;
var target = ev.target || ev.srcElement;
if(target.nodeName.toLowerCase() == 'li'){
alert('Delegate');
alert(target.innerHTML);
}
};
addLi.onclick = function(){
var addLiElement = document.createElement('li');
addLiElement .innerHTML = 10000*Math.random();
ulDelegate.appendChild(addLiElement );
}
}
看,上面是用事宜单例的体式格局,新增加的子元素是带有事宜结果的,我们不须要去遍历元素的子节点,只须要给父级元素增加事宜就好了,其他的都是在js内里的实行,如许能够大大的削减dom操纵,这才是事宜代办的精华地点。
总结
事宜是将javascript与网页联络在一起的主要体式格局,在运用事宜时,须要斟酌以下一些内存与机能方面的题目。
- 有必要限定夜歌页面中事宜处置惩罚顺序的数目,数目太多会致使占用大批内存,而且也会让用户页面回响反映不够敏锐
- 建立在事宜冒泡机制之上的时刻托付手艺,能够有用的削减时刻处置惩罚顺序的数目
- 发起在阅读器卸载页面之前移除页面中的一切事宜处置惩罚顺序
事宜是javascript中最主要的主题之一,深切明白事宜的事情机制以及它们对机能的影响是至关主要的
(总结摘自javascript高等顺序设计第三版)