JavaScript中的事件流是指從DOM中發生事件時的順序。當一個元素觸發事件時,可能會影響到它的子元素或它的父元素。因此,知道事件流的順序是非常重要的。
事件流有三個階段:捕獲階段、目標階段和冒泡階段。先來看看捕獲階段。
const div1 = document.querySelector('#div1'); const div2 = document.querySelector('#div2'); const div3 = document.querySelector('#div3'); div1.addEventListener('click', () => { console.log('div1 captured'); }, true); div2.addEventListener('click', () => { console.log('div2 captured'); }, true); div3.addEventListener('click', () => { console.log('div3 captured'); }, true); div3.addEventListener('click', () => { console.log('div3 bubbling'); }); div2.addEventListener('click', () => { console.log('div2 bubbling'); }); div1.addEventListener('click', () => { console.log('div1 bubbling'); });
在上面的代碼中,我們為每個div綁定了一個click事件監聽器。并且,我們在div1、div2、div3上的監聽器都使用了第三個參數true,表示在捕獲階段中監聽事件。
現在,如果我們在div3上點擊一下,會發生什么?以下是控制臺輸出:
div1 captured div2 captured div3 captured div3 bubbling div2 bubbling div1 bubbling
我們可以看到,結果按照定義的順序,事件先發生在了div1上,然后是div2,最后是div3。接下來事件開始在冒泡階段從子元素傳播到祖先元素,依次是div3、div2、div1。
接下來,我們來看看目標階段。舉個例子:
const btn = document.querySelector('#btn'); btn.addEventListener('click', () => { console.log('button clicked'); });
在這里,我們為按鈕綁定了一個click事件監聽器。如果我們點擊按鈕,將看到以下輸出:
button clicked
在目標階段中,事件只發生在被點擊的元素上。即使我們在按鈕的父元素上也綁定了click事件監聽器,它也不會被觸發。
最后是冒泡階段。這是JavaScript事件流的默認階段,它從事件目標元素開始,在DOM樹中向上冒泡傳播。也就是先在被點擊的元素上觸發事件,然后向它的父元素逐層傳遞。舉例:
const div1 = document.querySelector('#div1'); const div2 = document.querySelector('#div2'); const div3 = document.querySelector('#div3'); div1.addEventListener('click', () => { console.log('div1 bubbling'); }); div2.addEventListener('click', () => { console.log('div2 bubbling'); }); div3.addEventListener('click', () => { console.log('div3 bubbling'); }); div3.addEventListener('click', () => { console.log('div3 captured'); }, true); div2.addEventListener('click', () => { console.log('div2 captured'); }, true); div1.addEventListener('click', () => { console.log('div1 captured'); }, true);
以上代碼中,我們在每個div上都綁定了click事件監聽器,事件監聽器在冒泡階段中監聽事件。
現在,如果我們在div3上點擊一下,將看到以下輸出:
div3 captured div2 captured div1 captured div3 bubbling div2 bubbling div1 bubbling
和捕獲階段相比,順序相反。事件從div3開始冒泡,然后依次是div2和div1。最后,事件到達文檔根部。
在實際開發中,我們可以根據需要在不同的階段監聽事件從而觸發不同的處理程序。如果我們想在冒泡階段中處理事件,則只需省略addEventListener()中的第三個參數。例如:
const div1 = document.querySelector('#div1'); const div2 = document.querySelector('#div2'); const div3 = document.querySelector('#div3'); div1.addEventListener('click', () => { console.log('div1 bubbling'); }); div2.addEventListener('click', () => { console.log('div2 bubbling'); }); div3.addEventListener('click', () => { console.log('div3 bubbling'); });
在這個例子中,我們沒有為任何事件監聽器指定第三個參數。因此,所有的監聽器都將在冒泡階段中監聽事件。
總之,了解JavaScript事件流的順序對于編寫可維護的代碼和確保程序的正確性是非常重要的。