真实的国产乱ⅩXXX66竹夫人,五月香六月婷婷激情综合,亚洲日本VA一区二区三区,亚洲精品一区二区三区麻豆

成都創(chuàng)新互聯(lián)網(wǎng)站制作重慶分公司

js基礎(chǔ)之事件捕獲與冒泡原理

想要了解什么是事件捕獲與冒泡,需要先了解什么是事件。

創(chuàng)新互聯(lián)公司專注于企業(yè)全網(wǎng)營銷推廣、網(wǎng)站重做改版、開化網(wǎng)站定制設(shè)計、自適應(yīng)品牌網(wǎng)站建設(shè)、成都h5網(wǎng)站建設(shè)、商城網(wǎng)站定制開發(fā)、集團(tuán)公司官網(wǎng)建設(shè)、外貿(mào)網(wǎng)站制作、高端網(wǎng)站制作、響應(yīng)式網(wǎng)頁設(shè)計等建站業(yè)務(wù),價格優(yōu)惠性價比高,為開化等各大城市提供網(wǎng)站開發(fā)制作服務(wù)。

什么是事件?

我們知道,在前端開發(fā)中,JavaScript負(fù)責(zé)定義網(wǎng)頁的“行為”。這里所說的“定義”,其實(shí)指的是開發(fā)者可以通過JavaScript語言向?yàn)g覽器描述一些規(guī)則,瀏覽器按照這些規(guī)則與用戶進(jìn)行交互。比如開發(fā)者希望當(dāng)用戶點(diǎn)擊頁面上某個按鈕的時候,就彈出一個窗口,顯示特定的內(nèi)容。而當(dāng)用戶真正點(diǎn)擊這個按鈕的時候,瀏覽器將按照開發(fā)者定義的這個規(guī)則,去彈出指定的窗口,顯示指定的內(nèi)容。

在上面的例子中,瀏覽器是一切規(guī)則的執(zhí)行者,開發(fā)者是這些規(guī)則的制定者,而JavaScript只是開發(fā)者向?yàn)g覽器描述這些規(guī)則時所使用的的語言(否則瀏覽器無法知道開發(fā)者想要在什么情況下做什么事)。假如我們通過以下的語句向?yàn)g覽器描述了一條規(guī)則:


 
 

js基礎(chǔ)之事件捕獲與冒泡原理

頁面上現(xiàn)在有一個按鈕,我們首先使用原生DOM獲取這個按鈕,然后使用button.addEventListener(“click”, function(){})這樣的語法向?yàn)g覽器描述了一條規(guī)則:當(dāng)這個按鈕被點(diǎn)擊(click)時,彈出提示框,顯示“我被點(diǎn)擊了”。用戶點(diǎn)擊按鈕后網(wǎng)頁就會出現(xiàn)如下提示:

js基礎(chǔ)之事件捕獲與冒泡原理

瀏覽器把這次“點(diǎn)擊”稱為一個“事件”?!笆录庇糜诿枋鼋换ミ^程中某些特定的關(guān)鍵點(diǎn)(如點(diǎn)擊、鼠標(biāo)滑動、滾輪滾動、按下鍵盤、觸屏操作等,每個操作都對應(yīng)特定的事件,不過事件也可能與用戶行為無關(guān),比如網(wǎng)頁加載完畢也是一個事件)。而瀏覽器處理交互最重要的手段就是基于事件來執(zhí)行開發(fā)者定義好的回調(diào)函數(shù)(如在用戶“點(diǎn)擊按鈕”時“彈出窗口”,而定義“彈出窗口”行為的就是回調(diào)函數(shù),也就是addEventListener中的function)。

定義完這條規(guī)則,當(dāng)用戶點(diǎn)擊按鈕時,瀏覽器就會彈出上述窗口了。我們稱“點(diǎn)擊”這個事件是在這個按鈕上觸發(fā)的(因?yàn)槲覀兊幕卣{(diào)函數(shù)是綁定在這個按鈕上的)。

那什么是事件的捕獲與冒泡呢?

事件的捕獲與冒泡

這個問題與HTML的結(jié)構(gòu)息息相關(guān)。

在前端開發(fā)中,我們使用標(biāo)簽語言HTML來描述網(wǎng)頁結(jié)構(gòu),如一個標(biāo)題、一個段落、一個表格等,這些網(wǎng)頁元素描述了網(wǎng)頁上有哪些需要顯示的內(nèi)容,它們構(gòu)成了整個網(wǎng)頁的“骨骼”,通常是一種嵌套的結(jié)構(gòu),比如:


 
 ... //這是對網(wǎng)頁內(nèi)容的元描述
 
 
  //這是網(wǎng)頁需要渲染的真正內(nèi)容
 

標(biāo)題

這里是一個段落

上述網(wǎng)頁結(jié)構(gòu)示意圖如下(在沒有設(shè)置padding等屬性的情況下,子元素通常會填滿父元素,這里的內(nèi)間距只是為了說明元素的嵌套關(guān)系):

js基礎(chǔ)之事件捕獲與冒泡原理

我們看到,body元素是整個網(wǎng)頁的容器,它的內(nèi)部包含了一個div元素,而div的內(nèi)部又包含了兩個元素:h2和p。假如我們現(xiàn)在在p的內(nèi)部點(diǎn)擊了一下,那么請問我們有沒有點(diǎn)擊它的外部容器div,以及最外部的body呢?

從瀏覽器的角度來看,我們同時在點(diǎn)擊這三個元素。

想要證明這個結(jié)論非常簡單,只需要使用addEventListener向div和body各自綁定click事件,如果點(diǎn)擊p時也會被觸發(fā),那就說明上面的結(jié)論是正確的。毫無疑問,它們會被觸發(fā)。

那么問題來了,既然用戶同時在點(diǎn)擊這三個元素,瀏覽器應(yīng)該先執(zhí)行哪個元素定義的回調(diào)函數(shù)呢(由于JavaScript采用單線程模型,執(zhí)行回調(diào)函數(shù)必然有一定的先后順序)?

這個問題實(shí)際上是在說,對于嵌套的元素,應(yīng)該從內(nèi)向外還是從外向內(nèi)響應(yīng)事件。瀏覽器之爭的兩大對立方分別有自己的看法:Netscape公司認(rèn)為應(yīng)當(dāng)由最外層的body首先得到這個事件,其次是div,最后才是目標(biāo)元素p;而微軟的IE開發(fā)組則認(rèn)為,應(yīng)當(dāng)是內(nèi)部的p首先得到這個事件,然后是div,最后才是body。在沒有標(biāo)準(zhǔn)約束的情況下,兩者按照自己的想法去設(shè)計瀏覽器的事件模型,Netscape從外向內(nèi)傳播的模型在業(yè)內(nèi)被稱為事件捕獲模型,而微軟從內(nèi)向外傳播的模型則被稱為事件冒泡模型。

兩個模型雖然從思路上南轅北轍,但是都可以保證所有綁定的回調(diào)函數(shù)正確觸發(fā)(不過觸發(fā)順序是相反的。如果這個觸發(fā)順序很重要,那么在當(dāng)時,你的代碼可能只能在一個瀏覽器中正確運(yùn)行,或者去做惡心的瀏覽器兼容)。不過瀏覽器允許開發(fā)者在事件傳播的過程中阻止事件的繼續(xù)傳播,此時兩者的差異就變得極其明顯。

假如我們在定義點(diǎn)擊div元素的回調(diào)函數(shù)時阻止了事件的傳播:

div.addEventListener("click", function(e){
 ...
 e.stopPropagation(); //阻止事件繼續(xù)傳播
})

這個代碼會在兩種模型下產(chǎn)生巨大的差異。在捕獲模型中,由于最外部首先得到該事件,因此body的點(diǎn)擊事件首先被觸發(fā),之后是div的點(diǎn)擊事件。由于阻止了事件傳播,p元素不會觸發(fā)回調(diào)。而在冒泡模型中則恰恰相反,內(nèi)部的p首先得到該事件,其次才是div,因此觸發(fā)回調(diào)的將是p和div,body因?yàn)槭录]有冒泡上來而無法監(jiān)聽到該事件。同樣的代碼在兩種模型中產(chǎn)生了完全不同的行為,這對于開發(fā)者來說顯然是不可接受的(兩個模型都有自己的適用場景,也都有自己的合理性,因此對于模型的好壞不能一概而論)。

那么后來的國際標(biāo)準(zhǔn)組織是如何解決這個沖突的呢?答案就是由開發(fā)者自己選擇。

標(biāo)準(zhǔn)的事件綁定使用addEventListener函數(shù),它接收兩個必傳參數(shù)和一個可選參數(shù):必傳的為event(事件名,如"cick")和function(回調(diào)函數(shù)),可選的為useCapture(是否使用捕獲模型,默認(rèn)為false,根據(jù)MDN的接口說明,這里也可以傳入一個對象,為本次監(jiān)聽設(shè)置其他參數(shù),詳細(xì)請參考MDN接口文檔 - addEventListener)。

div.addEventListener("click", function(){}, true); //使用捕獲模型

第三個參數(shù)就是標(biāo)識開發(fā)者是否需要使用捕獲模型,默認(rèn)為false,也就是默認(rèn)使用微軟的冒泡模型(這是因?yàn)榇蠖鄶?shù)事件都只在最內(nèi)部的元素上觸發(fā),這也間接表明,冒泡模型的普適性更好)。如果開發(fā)者的需求確實(shí)需要使用捕獲模型,可以將第三個參數(shù)設(shè)置為true。比如下面的例子:

事件捕獲與冒泡的用法

了解了事件捕獲與冒泡的基本原理之后,我們舉個例子來說明這兩個模型的基本用法。

假設(shè)有以下的DOM結(jié)構(gòu):

這是兩個重疊的div,當(dāng)點(diǎn)擊時,兩者都會響應(yīng)這個click事件。假如事件綁定如下:

var outer = document.querySelector("#outer");
var inner = document.querySelector("#inner");
 outer.addEventListener("click", function(e){
 alert("來自外部div的消息");
 e.stopPropagation(); //阻止事件向內(nèi)部傳播
 }, true); //使用捕獲模型

 inner.addEventListener("click", function(e){
 alert("來自內(nèi)部div的消息");
 }, true); //使用捕獲模型

頁面上將只顯示外部彈出的消息,內(nèi)部的事件被e.stopPropagation()攔截了下來,導(dǎo)致事件沒有觸發(fā)。而如果寫成下面的代碼:

var outer = document.querySelector("#outer");
var inner = document.querySelector("#inner");
 outer.addEventListener("click", function(e){
 alert("來自外部div的消息");
 }, false); //使用冒泡模型

 inner.addEventListener("click", function(e){
 alert("來自內(nèi)部div的消息");
 e.stopPropagation(); //阻止事件向外部傳播
 }, false); //使用冒泡模型

這次是只顯示了內(nèi)部的消息,而沒有顯示外部的消息,說明事件在向上冒泡的過程中被阻止了。

注意

如果是在表格中內(nèi)嵌復(fù)選框,希望實(shí)現(xiàn)點(diǎn)擊一行時選中復(fù)選框,通過stopPropagation阻止CheckBox響應(yīng)click事件并不能實(shí)現(xiàn)。測試發(fā)現(xiàn)復(fù)選框狀態(tài)改變的事件似乎并不是在click事件觸發(fā)的(斷點(diǎn)跟蹤表明,CheckBox在執(zhí)行click回調(diào)之前,狀態(tài)就已經(jīng)發(fā)生了改變,具體是通過什么事件改變了選中狀態(tài)尚不清楚),下面給一個可以處理行點(diǎn)擊的示例:

表格第一行
表格第二行

這里沒有使用stopPropagation阻止事件傳播,而是通過為CheckBox定義額外的click事件來解決狀態(tài)不變的問題(經(jīng)過斷點(diǎn)跟蹤,此時在點(diǎn)擊CheckBox時,狀態(tài)發(fā)生了三次變化,第一次是觸發(fā)了某個原生事件導(dǎo)致其狀態(tài)變化,第二次是執(zhí)行了tr的點(diǎn)擊事件,第三次則是為CheckBox自定義的click事件)。也就是說,點(diǎn)擊tr時狀態(tài)改變一次,點(diǎn)擊CheckBox時狀態(tài)改變?nèi)危δ芫!?/p>

由于在大多數(shù)情況下,事件都是由最內(nèi)層的元素來處理的,所以冒泡模型的應(yīng)用更為廣泛,它也因此成為綁定事件時使用的默認(rèn)模型。

總結(jié)

事件的捕獲與冒泡兩個模型相對比較簡單,只要明白了其中的原理,就可以很容易掌握通過stopPropagation阻止事件傳播的使用。

瀏覽器的標(biāo)準(zhǔn)事件模型把事件的傳播過程分成了三個階段:捕獲階段、處于目標(biāo)階段和冒泡階段。捕獲階段指事件從最外層傳播到最內(nèi)層之前的整個過程,對應(yīng)捕獲模型;處于目標(biāo)階段指的是事件剛好傳播到目標(biāo)元素上;而冒泡階段指的是從最內(nèi)層元素向外傳播的整個過程。所以我們看到,標(biāo)準(zhǔn)的瀏覽器事件模型就是把捕獲模型和冒泡模型有機(jī)地結(jié)合起來,使開發(fā)者可以以最簡單的方式靈活地使用兩個模型。

以上就是本文的全部內(nèi)容,希望對大家的學(xué)習(xí)有所幫助,也希望大家多多支持創(chuàng)新互聯(lián)。


網(wǎng)站標(biāo)題:js基礎(chǔ)之事件捕獲與冒泡原理
網(wǎng)站鏈接:http://weahome.cn/article/jipjhj.html

其他資訊

在線咨詢

微信咨詢

電話咨詢

028-86922220(工作日)

18980820575(7×24)

提交需求

返回頂部