js事件系列
以前遇到相关的问题都没在意也没深究,常用到的就一个阻止冒泡event.stopPropagation() 每次连单词都是复制过去的。
今天找了几篇相关博客看了下算是理清了,特此总结一下也留个备忘。
先说事件流:
事件流指从页面中接收事件的顺序,有冒泡流和捕获流。
假如我们点击一个div,实际上是先点击document,然后点击事件传递到div,而且并不会在这个div就停下,div有子元素就还会向下传递,最后又会冒泡传递回document,如下图:
为了兼容更多的浏览器,一般我们都是把事件添加到在事件冒泡阶段。(IE8及以前只支持事件冒泡)。
当dom元素注册多个同种事件,事件发生的顺序按照添加的顺序依次触发(IE是相反的)。
添加和删除事件:
DOM事件通过addEventListener(添加)和removeEventListener(删除)管理。
两个方法都一样接收三个参数,第一个是要处理的事件名,第二个是事件处理程序,第三个值为false时表示在冒泡阶段调用处理程序,一般建议在冒泡阶段使用。
IE则用attachEvent(),detachEvent(),接收两个参数,事件名称和事件处理程序,通过attachEvent()添加的事件处理程序都会被添加到冒泡阶段。
事件对象event:
当触发DOM上的某个事件时,会产生一个事件对象event,这个对象中包含了所有与事件有关的信息。
比如导致事件的元素target,只有在事件处理程序执行期间,event对象才会存在,一旦事件处理程序执行完毕,event对象就会被销毁。
在事件处理程序中this === event.target
在IE中event参数是未定的,事件对象是作为window的一个属性存在的,因此可以通过window.event来访问event对象,不同于DOM级中event是作为参数直接传入和返回。
事件冒泡和事件捕获:
他们是描述事件触发时序问题的术语。
事件捕获指的是从document到触发事件的那个节点,即自上而下的去触发事件。
相反事件冒泡是自下而上的去触发事件。
绑定事件方法的第三个参数,就是控制事件触发顺序是否为事件捕获。
true-事件捕获,false-事件冒泡,默认false,即事件冒泡。
下面是demo演示冒泡和捕获:
<div id="parent"> <div id="child" class="child"></div> </div> ///////// document.getElementById("parent").addEventListener("click",function(e){ alert("parent事件被触发,"+this.id); }, false) document.getElementById("child").addEventListener("click",function(e){ alert("child事件被触发,"+this.id) }, false)
上面打印结果:
child事件被触发,child
parent事件被触发,parent
因为第三个参数是false所以是事件冒泡 就会先触发里面dom元素。
如果改为true则结果相反。
阻止事件冒泡捕获:
event.stopPropagation()不能简单说阻止了事件的冒泡,其实也阻止了事件的继续捕获,确切的说应该是阻止事件的进一步传播。
d1.addEventListener('click', function (event) { console.log('d1'); event.stopPropagation(); }, true);
事件委托:
也可以称为事件代理。用到这个是为了减少不必要的事件处理程序,达到性能优化减少内存的作用。
用法如下:
// 相同任务时 window.onload = function(){ var oUl = document.getElementById("ul1"); oUl.onclick = function(ev){ var ev = ev || window.event; var target = ev.target || ev.srcElement; if(target.nodeName.toLowerCase() == 'li'){ alert(123); alert(target.innerHTML); } } }
上面用父级ul做事件处理,当li被点击时,由于冒泡原理,事件就会冒泡到ul上,因为ul上有点击事件,所以事件就会触发,当然,这里当点击ul的时候,也是会触发的。
// 不同任务时 window.onload = function(){ var oBox = document.getElementById("box"); oBox.onclick = function (ev) { var ev = ev || window.event; var target = ev.target || ev.srcElement; if(target.nodeName.toLocaleLowerCase() == 'input'){ switch(target.id){ case 'add' : alert('添加'); break; case 'remove' : alert('删除'); break; case 'move' : alert('移动'); break; case 'select' : alert('选择'); break; } } } }