1. 程式人生 > >事件冒泡原理自我理解以及使用

事件冒泡原理自我理解以及使用

首先,這是我自己在學習過程中對於時間冒泡原理的理解,如果有不對的地方,讀者儘可提出,不斷學習。

一:事件冒泡和阻止冒泡以及使用場景:

1.事件冒泡,就是元素自身的事件被觸發後,如果父元素有相同的事件,如onclick事件,那麼元素本身的觸發狀態就會傳遞,也就是冒到父元素,父元素的相同事件也會一級一級根據巢狀關係向外觸發,直到document/window,冒泡過程結束。

2.比如:

<div class="box" styel="width:200px; height: 200px;background_color:'#ddd'">

<div class="box1" styel="width:200px; height: 200px;background_color:'#000'>

<div class="box2" styel="width:200px; height: 200px;background_color:'#eee'></div>

</div>

</div>

<script>

document.querySelector(".box").onclick=function(){

alert("我是box")

}

document.querySelector(".box1").onclick=function(){

alert("我是box1")

}

document.querySelector(".box2").onclick=function(){

alert("我是box2")

}

document.onclick=function(){

alert("我是document")

}

</script>

此時觸發box2中的額onclick事件,會依次彈出“我是box2” 我是box1 我是box1 我是document。這就是事件冒泡。

3.但是事件冒泡在某些應用場景產生一些問題,就是我們不需要觸發的事件,由於冒泡的原因,也會執行。所以在這個時候要取消事件冒泡。直接粘圖(不知道用什麼工具直接貼上程式碼,帶原格式的。。。)

    box.onmouseover = function (event) {
        // 阻止冒泡
        event = event || window.event;
        if(event && event.stopPropagation){
            event.stopPropagation();
        }else{
            event.cancelBubble = true;
        }
    }

4.那麼事件冒泡和組織冒泡什麼時候會用到呢?

記著只要是能夠觸發事件冒泡的情況下,就考慮取消事件冒泡,或者直接利用事件冒泡。

在這裡,有一個例子,可以實現阻止事件冒泡來實現,就是模態框的顯示和隱藏:(模態框不懂自行參考)。

    <div class="mask">
        <div class="login" id="login"></div>
    </div>
    <a href="#">註冊</a>
    <a href="#">登陸</a>
    <script>
        //1.給登入繫結事件
        var mask = document.getElementsByClassName("mask")[0];
        var a = document.getElementsByTagName("a")[1];
        a.onclick = function (event) {
            //顯示模態框
             ele.style.display = "block";
            //阻止冒泡
            event = event || window.event;
            if(event && event.stopPropagation){
                event.stopPropagation();
            }else{
                event.cancelBubble = true;
            }
        }
        //2.給document繫結事件,因為可以冒泡,只要判斷,點選的不是login,那麼隱藏模態框
           document.onclick = function (event) {
            // 獲取點選按鈕後傳遞過來的值。
            event = event || window.event;
            //相容獲取事件觸動時,被傳遞過來的物件
           var aaa = event.target || event.srcElement;
            var aaa = event.target?event.target:event.srcElement;
            console.log(event.target);
            //判斷目標值的ID是否等於login,如果等於不隱藏盒子,否則隱藏盒子。
            if(aaa.id !== "login"){
                mask.style.display = "none";
            }
            alert("123")
        }
    </script>

解釋:因為document和a都綁定了onclick事件,而且是巢狀的關係,當點選a標籤的時候,會造成事件冒泡,既會顯示mask模態框,又會彈出“123”的彈出框,所以我們要組織事件的冒泡。如上。

然後判斷點選的物件target是不是mask,如果不是mask,就執行mask.style.display="none",模態框消失。

二:事件委託:

1.剛開始接觸事件委託概念的時候,很是懵逼,搞不懂到底是一個怎樣的委託過程,怎麼實現的,但是學到一定程度回過頭來,也感覺很好理解。

個人認為事件冒泡存在的意義,就是在事件執行過程中,避免使用迴圈遍歷的方式去給每個同級元素觸發相同的事件,而優化效能。要知道,元素量無限大,迴圈遍歷是個噩夢,這也是網站效能優化的一個方面,就是儘量減少使用迴圈遍歷。好了,簡單說說我對事件委託理解,例項是摘抄過來的:

如果要實現列表中,當滑鼠over的時候,給每個li新增背景:一般想到的方法就是迴圈遍歷新增,如下:

<ul id="ul">
	<li>aaaaaaaa</li>
	<li>bbbbbbbb</li>
	<li>cccccccc</li>
</ul>
window.onload = function(){
	var oUl = document.getElementById("ul");
	var aLi = oUl.getElementsByTagName("li");

	for(var i=0; i<aLi.length; i++){
		aLi[i].onmouseover = function(){
			this.style.background = "red";
		}
		aLi[i].onmouseout = function(){
			this.style.background = "";
		}
	}
}
在元素個數不多的情況下可以使用,但元素很多的時候,不建議使用,建議使用冒泡的事件委託:原理如下:
window.onload = function(){
	var oUl = document.getElementById("ul");
	var aLi = oUl.getElementsByTagName("li");

/*
這裡要用到事件源:event 物件,事件源,不管在哪個事件中,只要你操作的那個元素就是事件源。
ie:window.event.srcElement
標準下:event.target
nodeName:找到元素的標籤名
*/
	oUl.onmouseover = function(ev){
		var ev = ev || window.event;
		var target = ev.target || ev.srcElement;
		//alert(target.innerHTML);
		if(target.nodeName.toLowerCase() == "li"){
		target.style.background = "red";
		}
	}
	oUl.onmouseout = function(ev){
		var ev = ev || window.event;
		var target = ev.target || ev.srcElement;
		//alert(target.innerHTML);
		if(target.nodeName.toLowerCase() == "li"){
		target.style.background = "";
		}
	}
}
只要判斷over或者out的物件,nodeName是不是"li",是的話就新增或者去掉背景。

2.還有一種情況:就是新新增的元素:

我們通常會使用Document.createElement("li");建立新的元素,然後再appendChild新增到父標籤中。但是有這樣一種情況,我是迴圈遍歷給每個li標籤綁定了滑鼠懸停現實背景色的事件,但這樣,新新增的元素就不會被迴圈到,因為新增之前已經迴圈停止了:所以:使用事件委託,就很好的解決了這個問題:

window.onload = function(){
	var oUl = document.getElementById("ul");
	var aLi = oUl.getElementsByTagName("li");
	var oBtn = document.getElementById("btn");
	var iNow = 4;

	oUl.onmouseover = function(ev){
		var ev = ev || window.event;
		var target = ev.target || ev.srcElement;
		//alert(target.innerHTML);
		if(target.nodeName.toLowerCase() == "li"){
		target.style.background = "red";
		}
	}
	oUl.onmouseout = function(ev){
		var ev = ev || window.event;
		var target = ev.target || ev.srcElement;
		//alert(target.innerHTML);
		if(target.nodeName.toLowerCase() == "li"){
		target.style.background = "";
		}
	}
	oBtn.onclick = function(){
		iNow ++;
		var oLi = document.createElement("li");
		oLi.innerHTML = 1111 *iNow;
		oUl.appendChild(oLi);
	}
}