在JavaScript中,事件傳播是一種重要的概念。當(dāng)HTML頁(yè)面中的某個(gè)元素觸發(fā)了某個(gè)事件時(shí),這個(gè)事件會(huì)沿著元素樹(shù)向上傳遞給父元素以及祖先元素或者向下傳遞到子元素和后代元素。這種傳播方式稱為事件傳播。
事件傳播分為三個(gè)階段:
1、事件捕獲階段(capturing phase) 事件從根元素一直往下傳遞,直到到達(dá)需要觸發(fā)事件的目標(biāo)元素。 2、目標(biāo)階段(target phase) 事件達(dá)到目標(biāo)元素,觸發(fā)對(duì)應(yīng)事件處理函數(shù)。 3、事件冒泡階段(bubbling phase) 事件從目標(biāo)元素依次往上,到達(dá)根元素。
舉個(gè)例子:
<div id="grandfather"> <div id="father"> <div id="son"></div> </div> </div>
假設(shè)我們給son元素綁定了一個(gè)點(diǎn)擊事件,我們來(lái)分析這個(gè)事件在不同階段分別會(huì)觸發(fā)哪些元素的事件處理函數(shù)。
son.addEventListener("click", function (event) { console.log("son被點(diǎn)擊了"); }); father.addEventListener("click", function (event) { console.log("father被點(diǎn)擊了"); }); grandfather.addEventListener("click", function (event) { console.log("grandfather被點(diǎn)擊了"); }, true);
上面的代碼使用addEventListener方法給son、father和grandfather分別綁定了一個(gè)“click”事件處理函數(shù),grandfather給它設(shè)置了第三個(gè)參數(shù)為true,表示在事件捕獲階段處理這個(gè)事件。
當(dāng)我們?cè)陧?yè)面上點(diǎn)擊son元素時(shí),會(huì)先由document對(duì)象開(kāi)始事件捕獲,一直傳遞到grandfather元素,觸發(fā)它的事件處理函數(shù)。隨后,son元素會(huì)觸發(fā)事件處理函數(shù),最后事件冒泡到grandfather元素,又會(huì)觸發(fā)一次事件處理函數(shù),輸出結(jié)果如下:
grandfather被點(diǎn)擊了 son被點(diǎn)擊了 grandfather被點(diǎn)擊了
事件的傳播還有一個(gè)比較有用的特性——事件委托。假設(shè)我們有一個(gè)列表元素,里面有很多l(xiāng)i元素。我們給列表元素綁定一個(gè)點(diǎn)擊事件處理函數(shù),但我們只想在點(diǎn)擊li元素時(shí)觸發(fā)這個(gè)處理函數(shù)。
<ul id="list"> <li>item1</li> <li>item2</li> <li>item3</li> <li>item4</li> </ul>
var list = document.getElementById("list"); list.addEventListener("click", function(event) { var target = event.target; if(target.tagName.toLowerCase() === "li") { console.log(target.innerText + "被點(diǎn)擊了"); } });
上面的代碼給列表元素list綁定了一個(gè)“click”事件處理函數(shù)。在這個(gè)處理函數(shù)里,我們通過(guò)event.target屬性來(lái)獲取當(dāng)前觸發(fā)事件的元素,如果這個(gè)元素的標(biāo)簽名為“l(fā)i”,我們就輸出它的innerText,也就是它里面的文本。
事件委托的好處在于,它可以減少事件處理函數(shù)的數(shù)量,代碼更加簡(jiǎn)潔,而且可以避免給每一個(gè)li元素都綁定一個(gè)處理函數(shù)的復(fù)雜性。
在實(shí)際開(kāi)發(fā)中,我們經(jīng)常需要處理一些復(fù)雜的事件流,如拖拽事件、鍵盤(pán)事件等。了解事件傳播是理解這些事件的關(guān)鍵。