什麼是事件流呢?本文主要和大家分享js事件流以及擴充應用程式實例以及擴充應用實例,希望能幫助大家。
DOM標準規定事件流包含三個階段:事件擷取階段、處於目標階段、事件冒泡階段。
● 事件捕獲階段:實際目標(<p></p>
)在捕獲階段不會接收事件。也就是在捕獲階段,事件從document到再到
就停止了。上圖為1~3.
● 處於目標階段:事件在<p></p>
上發生並處理。但是事件處理會被看成是冒泡階段的一部分。
● 冒泡階段:事件又傳回文件。
note:
1)、儘管「DOM2級事件」標準規範明確規定事件捕獲階段不會涉及事件目標,但是在IE9、Safari、Chrome、Firefox和Opera9.5及更高版本都會在捕獲階段觸發事件物件上的事件。結果,就是有兩次機會在目標物件上面操作事件。
2)、並非所有的事件都會經過冒泡階段 。所有的事件都要經過捕獲階段和處於目標階段,但是有些事件會跳過冒泡階段:如,獲得輸入焦點的focus事件和失去輸入焦點的blur事件。
捕捉型事件流:事件的傳播是從最不特定的事件目標到最特定的事件目標。即從DOM樹的根到葉子。
冒泡型事件流:事件的傳播是從最特定的事件目標到最不特定的事件目標。即從DOM樹的葉子到根。
那麼這裡要實現的就是冒泡型事件流,從裡面(葉子)到外面(根)
//只需要在window.onload里面给每一个圆添加点击事件处理程序就ok了哦,其余代码请看上[一篇文章](https://blog.csdn.net/weixin_38323736/article/details/79685589)当然是在圆画好之后执行这一段代码,所以位置放在后面,别放错var circles=document.getElementsByClassName("circle"); for(var i=0;i<n;i++){ circles[i].onclick=function(e){ //currentTarget表示当前处理该事件的元素、文档或窗口,childNodes是子节点的意思,这里遍历子节点 e.currentTarget.childNodes.forEach(function(v) { //把文本节点找出,不然html代码也会输出的 if(v instanceof Text) { //文字节点为Text()实例,用data或者wholeText可以取到String类型的文本 //解决方法参照:https://segmentfault.com/q/1010000009913772/a-1020000009914008 console.log(v.data); // console.log(v.wholeText); } }); } }
ok啦,就是這麼簡單。
好學的同學一定想看看事件捕獲了,乾脆我把兩種都寫出來吧,讓大家看看整個事件流是怎麼樣的
circles[i].onclick =function(e){}
這種寫法是dom0級的寫法,只能寫一個事件,再寫一個會覆蓋,而且只支援冒泡事件addEventListener
則不一樣,它可以寫多個事件,不會覆蓋
//这段代码包含了上面的js代码哦var circles=document.getElementsByClassName("circle");for(var i=0;i<n;i++){ circles[i].addEventListener("click",function(e){ e.currentTarget.childNodes.forEach(function(v) { if(v instanceof Text) { console.log(v.data+" 捕获阶段"); } }); //true表示事件句柄在捕获阶段执行; //false- 默认。事件句柄在冒泡阶段执行 },true); circles[i].addEventListener("click",function(e){ e.currentTarget.childNodes.forEach(function(v) { if(v instanceof Text) { console.log(v.data+" 冒泡阶段"); } }); },false); }
這時候,點擊15,就會出現下面的效果啦
ok啦,其實事件冒泡有一個很好的應用哦,就是事件代理
事件代理也即事件委託
傳統的事件處理中,需要為每個元素新增事件處理器。 js事件代理程式則是一種簡單有效的技巧,透過它可以把事件處理器加入到一個父級元素上,從而避免把事件處理器加入到多個子級元素上。
事件代理的原理用到的就是事件冒泡和目標元素,把事件處理器加入父元素,等待子元素事件冒泡,並且父元素能夠透過target(IE為srcElement)判斷是哪個子元素,從而做相應處理。
事件代理程式的好處
● 將多個事件處理器減少到一個,因為事件處理器要駐留內存,這樣就提高了效能。想像如果有一個100行的表格,對比傳統的為每個單元格綁定事件處理器的方式和事件代理(即table上添加一個事件處理器),不難得出結論,事件代理確實避免了一些潛在的風險,提高了性能。
● DOM更新無需重新綁定事件處理器,因為事件代理程式對不同子元素可採用不同處理方法。如果新增其他子元素(a,span,p等),直接修改事件代理程式的事件處理函數即可,不需要重新綁定處理器,不需要再次循環遍歷。
例如,現在我想,點擊15的圓的時候,就輸出15,我們先用傳統循環的方法來寫,再用事件委託的方法來寫
var circles=document.getElementsByClassName("circle");for(var i=0;i<n;i++){ circles[i].addEventListener("click",function(e){ e.currentTarget.childNodes.forEach(function(v) { if(v instanceof Text) { console.log(v.data); } }); //阻止冒泡哦!!!不然不止输出15了 e.stopPropagation(); },false); }
這種方法其實是耗性能的,循環幾次,編譯時就會寫幾次,所以還是不如事件代理,只需要寫一次:
//获取外面的大圆,只需要交给大圆来处理就okvar circle=document.getElementById("circle"); circle.addEventListener("click",function(e){ e=e||window.event; var targetElement=e.target||e.srcElement; targetElement.childNodes.forEach(function(v) { if(v instanceof Text) { console.log(v.data); } }); })
哈哈,有沒有人想問,那上面用了那麼多循環,怎麼不也用事件代理寫了呢?我想了一下,還真可以寫哦
var circle=document.getElementById("circle"); circle.addEventListener("click",function(e){ e=e||window.event; var targetElement=e.target||e.srcElement; while(targetElement.nodeName!="BODY"){ targetElement.childNodes.forEach(function(v) { if(v instanceof Text) { console.log(v.data); } }); targetElement=targetElement.parentNode; } },false)
相關推薦:
以上是js事件流以及擴充應用程式實例的詳細內容。更多資訊請關注PHP中文網其他相關文章!