最美情侣中文字幕电影,在线麻豆精品传媒,在线网站高清黄,久久黄色视频

歡迎光臨散文網(wǎng) 會員登陸 & 注冊

廣州藍景分享-搞懂js事件、事件流(捕獲冒泡)、事件委托

2020-12-11 11:52 作者:廣州藍景  | 我要投稿

JS事件詳解

javascriptHTML之間的交互是通過事件實現(xiàn)的。

事件就是用戶或瀏覽器自身執(zhí)行的某種動作,比如點擊、加載,鼠標(biāo)移入移出等等。

DOM事件流

事件流包括三個階段。簡而言之:事件一開始從文檔的根節(jié)點流向目標(biāo)對象(捕獲階段),然后在目標(biāo)對象上被觸發(fā)(目標(biāo)階段),之后再回溯到文檔的根節(jié)點(冒泡階段)。

DOM事件流:包括三個階段:

事件捕獲階段(Capture Phase)?事件的第一個階段是捕獲階段。事件從文檔的根節(jié)點出發(fā),隨著 DOM 樹的結(jié)構(gòu)向事件的目標(biāo)節(jié)點流去。途中經(jīng)過各個層次的 DOM 節(jié)點,并在各節(jié)點上觸發(fā)捕獲事件,直到到達事件的目標(biāo)節(jié)點。捕獲階段的主要任務(wù)是建立傳播路徑,在冒泡階段,事件會通過這個路徑回溯到文檔跟節(jié)點。

目標(biāo)階段(Target Phase)?當(dāng)事件到達目標(biāo)節(jié)點的,事件就進入了目標(biāo)階段。事件在目標(biāo)節(jié)點上被觸發(fā)(執(zhí)行事件對應(yīng)的函數(shù)),然后會逆向回流,直到傳播至最外層的文檔節(jié)點。

**冒泡階段(Bubble Phase)**事件在目標(biāo)元素上觸發(fā)后,并不在這個元素上終止。它會隨著 DOM 樹一層層向上冒泡,直到到達最外層的根節(jié)點。也就是說,同一個事件會依次在目標(biāo)節(jié)點的父節(jié)點,父節(jié)點的父節(jié)點...直到最外層的節(jié)點上被觸發(fā)。

所有的事件都要經(jīng)過捕捉階段和目標(biāo)階段,但是有些事件會跳過冒泡階段。例如,讓元素獲得輸入焦點的 focus 事件以及失去輸入焦點的 blur 事件就都不會冒泡。

事件類型

UI (User Interface) 事件,當(dāng)用戶與頁面上的元素交互時觸發(fā)

  • load、unload、error、select、resize、scroll

焦點事件,在頁面獲得或失去焦點時觸發(fā)

  • blur、focusout 失去焦點

  • focus、focusin 獲得焦點

鼠標(biāo)事件,用戶通過鼠標(biāo)在頁面執(zhí)行操作時觸發(fā)

  • click、dbclick、mousedown、mouseup

  • mouseenter、mouserleave

  • mousemove

  • mouseout、mouseover

  • 點擊和雙擊事件觸發(fā)的順序如下

    • mousedown

    • mouseup

    • click

    • mousedown

    • mouseup

    • dbclick


滾輪事件,當(dāng)使用鼠標(biāo)滾輪操作時觸發(fā)

  • mousewheel

文本事件,在文檔中輸入文本時觸發(fā)

  • textInput 當(dāng)用戶在可編輯區(qū)域中輸入字符時,就會觸發(fā)這個事件

鍵盤事件,當(dāng)用戶通過鍵盤在頁面上執(zhí)行操作時觸發(fā)

  • keydown 按下鍵盤任意鍵時觸發(fā),不松開,則一直觸發(fā)

  • keypress 按下鍵盤上的字符鍵時觸發(fā),不松開,則一直觸發(fā)

  • Keyup 用戶釋放鍵盤上的建時觸發(fā)

HTML5事件

  • contextmenu 事件:單價鼠標(biāo)右鍵可以調(diào)出上下文菜單

  • beforeunload 事件:在瀏覽器卸載頁面之前觸發(fā)

  • DOMContentLoad 事件:在形成完整的DOM樹之后就會觸發(fā)。

  • readystatechange 事件:提供與文檔加載狀態(tài)有關(guān)的信息

  • pageshow和pagehide 事件:頁面顯示和隱藏時觸發(fā)?MDN傳送門

  • hashchange 事件 : hash改變時觸發(fā)

除此之外,還有變動事件,復(fù)合事件,HTML5新加入的一些事件,不再一一列出。完整列表可在這里查看 Web Events

事件對象

event:MDN傳送門

在觸發(fā) DOM 上的某個事件時,會產(chǎn)生一個事件對象 event,這個對象中包含著所有與事件有關(guān)的信息。所有的瀏覽器都支持 event 對象,但支持方式不同。

常用屬性:

target?事件的目標(biāo)

currentTarget?綁定事件的元素,與 'this' 的指向相同

stopPropagation()?取消事件的進一步捕獲或冒泡。如果bubbles為true,則可以使用這個方法

stopImmediatePropagation()?方法阻止監(jiān)聽同一事件的其他事件監(jiān)聽器被調(diào)用。

如果多個事件監(jiān)聽器被附加到相同元素的相同事件類型上,當(dāng)此事件觸發(fā)時,它們會按其被添加的順序被調(diào)用。如果在其中一個事件監(jiān)聽器中執(zhí)行 stopImmediatePropagation() ,那么剩下的事件監(jiān)聽器都不會被調(diào)用。

preventDefault()?取消事件的默認行為,比如點擊鏈接跳轉(zhuǎn)。如果?cancelable?是?true,則可以使用這個方法

type?被觸發(fā)的事件類型

eventPhase?調(diào)用事件處理程序的階段:1表示捕獲階段,2表示“處于目標(biāo)”,3表示冒泡階段

更多詳情參見:跨瀏覽器的事件對象

<!DOCTYPE html>

<html lang="en">

<head> ?


? ? ?<meta charset="UTF-8"> ?

?<meta name="viewport" content="width=device-width, initial-scale=1.0"> ? ?<title>Document</title> ?

?<style> ? ? ? ?

? ? ? .btnCon { ? ? ?

? ? ?width: 300px; ? ? ??

? ? ?height: 300px; ? ? ?

? ? ?border: 1px solid yellow; ? ?

} ? ??

? ?.btn { ? ??

? ? ? ?width: 200px; ? ? ?

? ? ?height: 200px; ? ?

? ?} ? ? ?

?.btn div { ? ? ?

? ? ?width: 100px; ? ??

? ? ?height: 100px; ? ? ?

? ? ?border: 1px solid red; ? ?

} ? ? ?

?.btn div span { ? ? ?

? ? ?background-color: #ccc; ? ?

} ?

?</style>

</head>

<body> ?

?<div class="btnCon"> ? ??

? ?<button class="btn"> ? ? ??

? ? ?<div> ? ? ? ? ?

? ? ?<span>按鈕</span> ? ? ?

? ? ?</div> ? ?

? ?</button> ??

?</div> ??

?<script> ? ?

?? ?let btnCon = document.querySelector('.btnCon'); ??

? ? ?let btn = document.querySelector('.btnCon div'); ? ??

? ?// btn.onclick = c; ? ?

?? ?btnCon.addEventListener('click', c); ? ??

? ?btn.addEventListener('click', c); ? ?

? ?// btn.addEventListener('click', c, true); ? ?

? ?function c(event) { ? ? ??

? ? ?event = event || wind ? ? ??

? ? ?console.log(event ); ? ? ?

?? ? ?//事件的目標(biāo) ? ? ??

? ? ?console.log('事件的目標(biāo) =>', event.target); ? ? ?

?? ? ?//綁定事件的元素,與 'this' 的指向相同 ? ? ?

?? ? ?console.log("綁定事件的元素 =>", event.currentTarget); ? ? ? ? ? ?console.log(event.currentTarget === event.target); ? ??

? ? ? ?//被觸發(fā)的事件類型 ? ? ?

?? ? ?console.log("被觸發(fā)的事件類型 => ",event.type); ? ??

? ? ? ?//調(diào)用事件處理程序的階段:0表示這個時間沒有事件正在被處理,1表示捕獲階段,2表示“處于目標(biāo)”,3表示冒泡階段 ? ? ? ?

? ?console.log('調(diào)用事件處理程序的階段:0表示這個時間沒有事件正在被處理,1表示捕獲階段,2表示“處于目標(biāo)”,3表示冒泡階段'); ? ? ? ? ? ?

console.log(event.eventPhase); ? ? ? ?

?? ?//取消事件的進一步捕獲或冒泡。如果bubbles為true,則可以使用這個方法 ? ? ? ? ? ?event.stopPropagation(); ? ? ??

? ? ?//取消事件的進一步捕獲或冒泡,同時阻止任何事件處理程序被調(diào)用(DOM3級事件中新增) ? ? ??

? ? ?event.stopImmediatePropagation(); ? ? ??

? ? ?//取消事件的默認行為,比如點擊鏈接跳轉(zhuǎn)。如果 cancelable 是 true,則可以使用這個方法 ? ? ??

? ? ?event.preventDefault(); ? ?

?? ?} ??

?</script>

</body>

</html>

阻止事件冒泡/停止傳播(Stopping Propagation)

可以通過調(diào)用事件對象的 stopPropagation 方法,在任何階段(捕獲階段或者冒泡階段)中斷事件的傳播。此后,事件不會在后面?zhèn)鞑ミ^程中的經(jīng)過的節(jié)點上調(diào)用任何的監(jiān)聽函數(shù)。

調(diào)用?event.stopPropagation()不會阻止當(dāng)前節(jié)點上此事件其他的監(jiān)聽函數(shù)被調(diào)用。如果你希望阻止當(dāng)前節(jié)點上的其他回調(diào)函數(shù)被調(diào)用的話,你可以使用更激進的event.stopImmediatePropagation()方法。

阻止瀏覽器默認行為

當(dāng)特定事件發(fā)生的時候,瀏覽器會有一些默認的行為作為反應(yīng)。最常見的事件不過于 link 被點擊。當(dāng)一個 click 事件在一個<a>元素上被觸發(fā)時,它會向上冒泡直到 DOM 結(jié)構(gòu)的最外層 document,瀏覽器會解釋 href 屬性,并且在窗口中加載新地址的內(nèi)容。

在 web 應(yīng)用中,開發(fā)人員經(jīng)常希望能夠自行管理導(dǎo)航(navigation)信息,而不是通過刷新頁面。為了實現(xiàn)這個目的,我們需要阻止瀏覽器針對點擊事件的默認行為,而使用我們自己的處理方式。這時,我們就需要調(diào)用?event.preventDefault().

我們可以阻止瀏覽器的很多其他默認行為。比如,我們可以在 HTML5 游戲中阻止敲擊空格時的頁面滾動行為,或者阻止文本選擇0框的點擊行為。

調(diào)用 event.stopPropagation()只會阻止傳播鏈中后續(xù)的回調(diào)函數(shù)被觸發(fā)。它不會阻止瀏覽器的自身的行為。

事件處理程序

HTML 事件處理程序

當(dāng)然在 HTML 中定義的事件處理程序也可以調(diào)用其它地方定義的腳本:


通過 HTML 指定的事件處理程序都需要HTML的參與,即結(jié)構(gòu)和行為相耦合,不易維護。

DOM0 級事件處理程序

這里是將一個函數(shù)賦值給一個事件處理程序的屬性,以這種方式添加的事件處理程序會在事件流的冒泡階段被處理。要刪除事件將 btn.onclick 設(shè)置為?null?即可。

DOM2 級事件處理程序

DOM2 級事件定義了addEventListener()?和?removeEventListener()兩個方法,用于添加和刪除事件處理程序的操作。

所有 DOM 節(jié)點都包含這兩個方法,它們接受3個參數(shù):要處理的事件名作為事件處理程序的函數(shù)和一個布爾值。最后的布爾值參數(shù)是?true 表示在捕獲階段調(diào)用事件處理程序,如果是?false(默認) 表示在冒泡階段調(diào)用事件處理程序。

通過上面例子可以看出,同一個dom元素,可以通過addEventListener()添加多個事件

上面代碼兩個事件處理程序會按照它們的添加順序觸發(fā),先輸出 btn 再輸出 Hello word!,

通過?addEventListener()添加的事件處理程序只能使用?removeEventListener()來移除,移除時傳入的參數(shù)與添加時使用的參數(shù)相同,即匿名函數(shù)無法被移除。

IE 事件處理程序

IE通常都是特立獨行的,它添加和刪除事件處理程序的方法分別是:attachEvent()?和detachEvent()

同樣接受事件處理程序名稱與事件處理程序函數(shù)兩個參數(shù),但跟**addEventListener()**的區(qū)別是:

  • 事件名稱需要加“on”,比如“onclick”;

  • 沒了第三個布爾值,IE8及更早版本只支持事件冒泡;

  • 仍可添加多個處理程序,但觸發(fā)順序是反著來的。

還有一點需要注意,DOM0 和 DOM2 級的方法,其作用域都是在其所依附的元素當(dāng)中,attachEvent()則是全局,即如果像之前一樣使用this.id,訪問到的就不是 button 元素,而是 window,就得不到正確的結(jié)果。

封裝兼容瀏覽器事件處理

事件委托/代理事件監(jiān)聽

事件委托利用了事件冒泡,只指定一個事件處理程序,就可以管理某一類型的所有事件。例如,click 事件會一直冒泡到 document 層次(根元素),也就是說,我們可以為整個頁面指定一個 onclick 事件處理程序,而不必為每個可點擊的元素分別添加事件處理程序。

事件委托的優(yōu)點

  • 可以大量節(jié)省內(nèi)存占用,減少事件注冊

  • 可以實現(xiàn)當(dāng)新增子對象時無需再次對其綁定(動態(tài)綁定事件)

使用事件委托注意事項

使用“事件委托”時,并不是說把事件委托給的元素越靠近頂層就越好。

事件冒泡的過程也需要耗時,越靠近頂層,事件的”事件傳播鏈”越長,也就越耗時。

如果DOM嵌套結(jié)構(gòu)很深,事件冒泡通過大量祖先元素會導(dǎo)致性能損失。

上面例子中的EVentUtil對象,是我們之前封裝的,可以往上看看

  • 通過上面例子可以看到, 我們在ul 標(biāo)簽 id="myLinks" 綁定了事件,

  • 然后我們可以通過點擊不同的li,li通過事件冒泡,來觸發(fā)到ul綁定的事件,

  • 這樣在事件對應(yīng)的函數(shù)內(nèi)寫上判斷,

  • 我們就可以通過點擊不同的li,就可以執(zhí)行相應(yīng)的代碼了

  • 就不用給每個li綁定事件,而且以后新增li也綁定事件,統(tǒng)一在ul綁定了事件,這也就是動態(tài)綁定事件

移除事件處理程序

內(nèi)存中留有那些過時不用的“空事件處理程序”,也是造成 web 應(yīng)用程序內(nèi)存與性能問題的主要原因。

在兩種情況下,可能會造成上述問題:

第一種情況就是從文檔中移除帶有事件處理程序的元素時。這可能是通過純粹的DOM操作,例如使用removeChild()replaceChild()方法,但更多地是發(fā)生在使用?innerHTML?替換頁面中某一部分的時候。如果帶有事件處理程序的元素被?innerHTML?刪除了,那么原來添加到元素中的事件處理程序極有可能被當(dāng)作垃圾回收。來看下面的例子:

這里,有一個按鈕被包含在<div>元素中,為避免雙擊,單擊這個按鈕時就將按鈕移除并替換成一條消息;這是網(wǎng)站設(shè)計中非常流行的一種做法。但問題在于,當(dāng)按鈕被從頁面中移除時,它還帶著一個事件處理程序呢,在<div>元素中設(shè)置 innerHTML 可以把按鈕移走,但事件處理各種仍然與按鈕保持著引用聯(lián)系。有的瀏覽器(尤其是IE)在這種情況下不會作出恰當(dāng)?shù)奶幚恚鼈兒苡锌赡軙υ睾褪录幚沓绦虻囊枚急4嬖趦?nèi)存中。如果你想知道某個元即將被移除,那么最好手工移除事件處理程序。如下面的例子所示:


在此,我們設(shè)置<div>的innerHTML屬性之前,先移除了按鈕的事件處理程序。這樣就確保了內(nèi)存可以被再次利用,而從DOM中移除按鈕也做到了干凈利索。

注意,在事件處理程序中刪除按鈕也能阻止事件冒泡。目標(biāo)元素在文檔中是事件冒泡的前提, 有元素節(jié)點才能冒泡上去。

**導(dǎo)致“空事件處理程序”的另一情況,就是卸載頁面中的時候。**毫不奇怪,IE在這種情況下依然是問題最多的瀏覽器,盡管其他瀏覽器或多或少也有類似的問題。如果在頁面被卸載之前沒有清理干凈事件處理程序。那它們就會滯留在內(nèi)存中。每次加載完頁面再卸載頁面時(可能是在兩個頁面間來加切換,也可以是單擊了“刷新”按鈕),內(nèi)存中滯留的對象數(shù)目就會增加,因為事件處理程序占用的內(nèi)存并沒有被釋放。

一般來說,最好的做法是在頁面卸載之前 ,先通過?onunload?事件處理程序移除所有事件處理程序。在此,事件委托技術(shù)再次表現(xiàn)出它的優(yōu)勢——需要跟蹤的事件程序越少,移除它們就越容易,對這種類似的操作,我們可把它想象成:只要是通過?onload?事件處理程序添加的東西,最后都要通過?onunload?事件處理程序?qū)⑺鼈円瞥?/p>

一些常用事情的操作

load 事件:

load 事件可以在任何資源(包括被依賴的資源)被加載完成時被觸發(fā),這些資源可以是圖片,css,腳本,視頻,音頻等文件,也可以是 document 或者 window。

Image 元素 load:


注意:新圖像元素不一定要添加到文檔后才開始下載,只要設(shè)置了 src 屬性就會開始下載。

script 元素 load:


與圖像不同,只有設(shè)置了 script 元素的 src 屬性并將元素添加到文檔后,才會開始下載 js 文件

onbeforeunload 事件(HTML5事件):?監(jiān)聽關(guān)閉頁面事件

window.onbeforeunload?讓開發(fā)人員可以在想用戶離開一個頁面的時候進行確認。這個在有些應(yīng)用中非常有用,比如用戶不小心關(guān)閉瀏覽器的 tab,我們可以要求用戶保存他的修改和數(shù)據(jù),否則將會丟失他這次的操作。

需要注意的是,對頁面添加?onbeforeunload?處理會導(dǎo)致瀏覽器不對頁面進行緩存,這樣會影響頁面的訪問響應(yīng)時間。 同時,onbeforeunload?的處理函數(shù)必須是同步的(synchronous)。

resize 事件:?監(jiān)聽頁面大小變化事件

在一些復(fù)雜的響應(yīng)式布局中,對 window 對象監(jiān)聽 resize 事件是非常常用的一個技巧。僅僅通過 css 來達到想要的布局效果比較困難。很多時候,我們需要使用 JavaScript 來計算并設(shè)置一個元素的大小。

error 事件:

當(dāng)我們的應(yīng)用在加載資源的時候發(fā)生了錯誤,我們很多時候需要去做點什么,尤其當(dāng)用戶處于一個不穩(wěn)定的網(wǎng)絡(luò)情況下。Financial Times 中,我們使用 error 事件來監(jiān)測文章中的某些圖片加載失敗,從而立刻隱藏它。由于“DOM Leven 3 Event”規(guī)定重新定義了 error 事件不再冒泡,我們可以使用如下的兩種方式來處理這個事件。

不幸的是,addEventListener 并不能處理所有的情況。而確保圖片加載錯誤回調(diào)函數(shù)被執(zhí)行的唯一方式是使用讓人詬病內(nèi)聯(lián)事件處理函數(shù)(inline event handlers)。

<img src="http://example.com/image.jpg" onerror="this.style.display='none';" />

原因是你不能確定綁定 error 事件處理函數(shù)的代碼會在 error 事件發(fā)生之前被執(zhí)行。而使用內(nèi)聯(lián)處理函數(shù)意味著在標(biāo)簽被解析并且請求圖片的時候,error監(jiān)聽器也將并綁定。

當(dāng)JavaScript運行時錯誤(包括語法錯誤)發(fā)生時,window會觸發(fā)一個ErrorEvent接口的error事件,并執(zhí)行window.onerror()。

加載一個全局的error事件處理函數(shù)可用于自動收集錯誤報告。

window.onerror = function(message, source, lineno, colno, error) { ... }

函數(shù)參數(shù):

  • message:錯誤信息(字符串)??捎糜贖TML onerror=""處理程序中的event。

  • source:發(fā)生錯誤的腳本URL(字符串)

  • lineno:發(fā)生錯誤的行號(數(shù)字)

  • colno:發(fā)生錯誤的列號(數(shù)字)

  • error:Error對象(對象)

若該函數(shù)返回true,則阻止執(zhí)行默認事件處理函數(shù)。

window.addEventListener('error', function(event) { ... })

window.error詳情;



廣州藍景分享-搞懂js事件、事件流(捕獲冒泡)、事件委托的評論 (共 條)

分享到微博請遵守國家法律
长治市| 青冈县| 新邵县| 南漳县| 关岭| 东乌| 衡阳市| 邳州市| 平塘县| 天峨县| 苍南县| 丹棱县| 张家港市| 综艺| 新蔡县| 平乡县| 漠河县| 海淀区| 和静县| 祁东县| 阿瓦提县| 翁源县| 六枝特区| 北票市| 运城市| 土默特右旗| 辉县市| 兴义市| 丹棱县| 集贤县| 多伦县| 巨鹿县| 托里县| 北宁市| 北川| 荔波县| 临沭县| 商都县| 缙云县| 栾城县| 曲靖市|