事件冒泡原理自我理解以及使用
首先,這是我自己在學習過程中對於時間冒泡原理的理解,如果有不對的地方,讀者儘可提出,不斷學習。
一:事件冒泡和阻止冒泡以及使用場景:
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);
}
}