日本不卡不码高清免费观看,久久国产精品久久w女人spa,黄色aa久久,三上悠亚国产精品一区二区三区

您的位置:首頁技術(shù)文章
文章詳情頁

理解JavaScript中的事件路由冒泡過程及委托代理機(jī)制

瀏覽:92日期:2023-11-23 08:51:46

當(dāng)我用純CSS實(shí)現(xiàn)這個以后。我開始用JavaScript和樣式類來完善功能。

然后,我有一些想法,我想使用Delegated Events (事件委托)但是我不想有任何依賴,插入任何庫,包括jQuery。我需要自己實(shí)現(xiàn)事件委托了。

我們先來看看事件委托到底是什么?他們是怎么工作的,怎么去實(shí)現(xiàn)這種機(jī)制。

好,它解決了什么問題?

我們先看個簡單的例子。

先假設(shè)我們有一組按鈕,我一次點(diǎn)擊一個按鈕,然后我希望被點(diǎn)中的狀態(tài)設(shè)為"active"。再次點(diǎn)擊時取消active。

然后,我們可以寫一些HTML:

<ul class="toolbar"> <li><button class="btn">Pencil</button></li> <li><button class="btn">Pen</button></li> <li><button class="btn">Eraser</button></li></ul>

我可以用一些標(biāo)準(zhǔn)的Javascript事件處理上面的邏輯:

var buttons = document.querySelectorAll(".toolbar .btn");for(var i = 0; i < buttons.length; i++) { var button = buttons[i]; button.addEventListener("click", function() { if(!button.classList.contains("active")) button.classList.add("active"); else button.classList.remove("active"); });}

看上去不錯,但是它其實(shí)不能像你期望的那樣工作。

閉包的陷阱

如果你有一定的JavaScript開發(fā)經(jīng)驗(yàn),這個問題就很明顯了。

對于外行來說button變量是被封閉的,每次都會找到對應(yīng)的button……但是其實(shí)這里只有一個button;每次循環(huán)都會被重新分配。

第一個循環(huán)它指向第一個button,接下來是第二個。但當(dāng)你點(diǎn)擊時button變量永遠(yuǎn)只指向最后一個button元素,問題出在這。

我們需要的是一個穩(wěn)定的作用域;讓我們重構(gòu)一下。

var buttons = document.querySelectorAll(".toolbar button");var createToolbarButtonHandler = function(button) { return function() { if(!button.classList.contains("active")) button.classList.add("active"); else button.classList.remove("active"); };};for(var i = 0; i < buttons.length; i++) { buttons[i].addEventListener("click", createToolBarButtonHandler(buttons[i]));}

注* 上面這段代碼結(jié)構(gòu)有點(diǎn)復(fù)雜,也可以簡單直接地使用一個閉包,封閉保存當(dāng)前的button變量,如下所示:

var buttons = document.querySelectorAll(".toolbar .btn");for(var i = 0; i < buttons.length; i++) { (function(button) { button.addEventListener("click", function() { if(!button.classList.contains("active"))button.classList.add("active"); elsebutton.classList.remove("active"); }); })(buttons[i])}

現(xiàn)在它能正常工作了。指向永遠(yuǎn)是正確的button

那么這個方案有什么問題?

這個方案看上去還可以,然而我們確實(shí)可以做得更好。

首先我們創(chuàng)建了太多的處理函數(shù)。為每一個匹配的.toolbar button綁定了一個事件偵聽和一個回調(diào)處理。假如只有三個按鈕這種資源分配是可以忽略的。

然而,如果我們有1000個呢?

<ul class="toolbar"> <li><button id="button_0001">Foo</button></li> <li><button id="button_0002">Bar</button></li> // ... 997 more elements ... <li><button id="button_1000">baz</button></li></ul>

它也不會崩潰,但是這并不是最佳的方案。我們分配了大量不必要的函數(shù)。讓我們重構(gòu)一下,僅附加一次,即僅綁定一個函數(shù)(function),去處理這種有可能的數(shù)千次調(diào)用。

相對于封閉button變量去存儲當(dāng)時我們點(diǎn)擊的對象,我們可以使用event對象去獲取當(dāng)時點(diǎn)擊的對象。

event對象有一些元數(shù)據(jù),在多次綁定的種情況下,我們可以使用currentTarget獲取當(dāng)前綁定的對象,如上例的代碼就可以改成:

var buttons = document.querySelectorAll(".toolbar button");var toolbarButtonHandler = function(e) { var button = e.currentTarget; if(!button.classList.contains("active")) button.classList.add("active"); else button.classList.remove("active");};for(var i = 0; i < buttons.length; i++) { button.addEventListener("click", toolbarButtonHandler);}

不錯!不過這只是簡化了單個函數(shù),讓它得更具可讀性,然而它還是被綁定了多次。

但是,我們還可以做得更好。

讓我們假設(shè)一下,我們在這個列表里動態(tài)地添加了一些按鈕。然后我們還要為這些動態(tài)元素添加和移除事件綁定。然后我們還要持久化這些處理函數(shù)和當(dāng)前上下文要用到的變量,這事聽上去就不靠譜。

也許還有其他方法。

讓我們先全面理解一下事件的工作原理,以及他們在DOM里是怎樣傳遞的。

事件的工作原理

當(dāng)用戶點(diǎn)擊一個元素時,一個事件就會被產(chǎn)生去通知用戶當(dāng)前的行為。事件在分發(fā)派遣時會有三個階段:

捕獲階段: Capturing 觸發(fā)階段: Target冒泡階段: Bubbling

這個事件起始從document之前然后一路向下找到當(dāng)前事件點(diǎn)擊到的對象。當(dāng)事件達(dá)到點(diǎn)擊到的對象之后,它會按原路返回(冒泡過程),直到退出整個DOM樹。

這里是一個HTML的例子:

<html><body> <ul> <li id="li_1"><button id="button_1">Button A</button></li> <li id="li_2"><button id="button_2">Button B</button></li> <li id="li_3"><button id="button_3">Button C</button></li> </ul></body></html>

當(dāng)你單擊Button A時,事件經(jīng)過的路徑會向下面這樣:

START| #document | HTML|| BODY } CAPTURE PHASE| UL || LI#li_1 /| BUTTON <-- TARGET PHASE| LI#li_1 | UL || BODY } BUBBLING PHASE | HTML|v #document /END

注意,這意思著你可以在事件的經(jīng)過路徑上捕獲到你單擊所產(chǎn)生的事件,我們非常確定這個事件一定會經(jīng)過他們的父元素ul元素。我們可以將我們的事件處理綁定到父元素上面,然后簡化我們的解決方案,這個就叫事件的委托及代理(Delegated Events)。

注* 其實(shí)Flash/Silverlight/WPF開發(fā)的事件機(jī)制是非常近似的,這里有一張他們的事件流程圖。 除了Silverlight 3使用了舊版IE的僅有冒泡階段的事件模型外,基本上也都有這三個階段。(舊版IE和SL3的事件處理只有一個從觸發(fā)對象冒泡到根對象的過程,可能是為了簡化事件的處理機(jī)制。)

理解JavaScript中的事件路由冒泡過程及委托代理機(jī)制

事件委托代理

委托(代理)事件是那些被綁定到父級元素的事件,但是只有當(dāng)滿足一定匹配條件時才會被挪。

讓我們看一個具體的例子,我們看看上文的那個工具欄的例子:

<ul class="toolbar"> <li><button class="btn">Pencil</button></li> <li><button class="btn">Pen</button></li> <li><button class="btn">Eraser</button></li></ul>

因?yàn)槲覀冎绬螕鬮utton元素會冒泡到UL.toolbar元素,讓我們將事件處理放到這里試試。我們需要稍微調(diào)整一下:

var toolbar = document.querySelector(".toolbar");toolbar.addEventListener("click", function(e) { var button = e.target; if(!button.classList.contains("active")) button.classList.add("active"); else button.classList.remove("active");});

這樣我們清理了大量的代碼,再也沒有循環(huán)了。注意我們使用了e.target代替了之前的e.currentTarget。這是因?yàn)槲覀冊谝粋€不同的層次上面進(jìn)行了事件偵聽。

e.target 是當(dāng)前觸發(fā)事件的對象,即用戶真正單擊到的對象。e.currentTarget 是當(dāng)前處理事件的對象,即事件綁定的對象。

在我們的例子中e.currentTarget就是UL.toolbar。

注* 其實(shí)不止事件機(jī)制,在整個UI構(gòu)架上FLEX(不是Flash) /Silverlight /WPF /Android的實(shí)現(xiàn)跟WEB也非常相似,都使用XML(HTML)實(shí)現(xiàn)模板及元素結(jié)構(gòu)組織,Style(CSS)實(shí)現(xiàn)顯示樣式及UI,腳本(AS3,C#,Java,JS)實(shí)現(xiàn)控制。不過Web相對其他平臺更加開放,不過歷史遺留問題也更多。但是幾乎所有的平臺都支持Web標(biāo)準(zhǔn),都內(nèi)嵌有類似WebView這樣的內(nèi)嵌Web渲染機(jī)制,相對各大平臺復(fù)雜的前端UI框架和學(xué)習(xí)曲線來說,使用Web技術(shù)實(shí)現(xiàn)Native APP的前端UI是非常低成本的一項(xiàng)選擇。

原文地址: codepen.io

標(biāo)簽: JavaScript
相關(guān)文章:
日本不卡不码高清免费观看,久久国产精品久久w女人spa,黄色aa久久,三上悠亚国产精品一区二区三区
美国三级日本三级久久99| 精品一区二区三区免费看| 久久av网址| 国产精品高清一区二区| 综合激情网站| 欧美日韩一视频区二区| 日韩av在线免费观看不卡| 青草综合视频| 在线看片国产福利你懂的| 亚洲欧洲国产精品一区| 亚洲伊人精品酒店| 91成人在线精品视频| 国产精品一区二区三区www| 久久av综合| 精品国模一区二区三区| 亚洲欧美日本视频在线观看| 亚洲精品人人| 91嫩草亚洲精品| 久久夜色精品| 亚洲视频播放| 欧美国产不卡| 91精品蜜臀一区二区三区在线| 伊人精品视频| 国产精品玖玖玖在线资源| 性感美女一区二区在线观看| 99国产成+人+综合+亚洲欧美| 日韩不卡一区二区三区| 国产一区二区三区久久| 久久成人一区| 狠狠久久伊人| 日韩精品一级| 国产欧美日韩一级| 好看的av在线不卡观看| 亚洲一区欧美| 国产精品久久久亚洲一区| 久久男人av资源站| 婷婷综合一区| 久久国产中文字幕| 麻豆精品视频在线观看免费| 在线亚洲一区| 欧美日韩国产v| 麻豆国产精品| 日韩精品福利一区二区三区| 日韩精品欧美| 岛国av在线网站| 国产精品v一区二区三区| 亚洲香蕉视频| 亚洲一区二区日韩| 国产日韩专区| 国产美女高潮在线| 久久永久免费| 国产精品极品| 欧美亚洲综合视频| 四虎精品一区二区免费| 麻豆亚洲精品| 美女网站久久| 久久久精品五月天| 鲁大师成人一区二区三区| 久久九九精品| 久久天堂av| 国产精品av一区二区| 高清av不卡| 精品久久免费| 日韩毛片视频| 伊人久久av| 欧美片第1页| 亚洲激精日韩激精欧美精品| 欧美69视频| 亚洲欧美日本国产专区一区| 免费久久99精品国产自在现线| 国产午夜精品一区二区三区欧美 | 1024精品一区二区三区| 999国产精品999久久久久久| 99免费精品| 激情六月综合| 欧产日产国产精品视频| 亚洲天堂成人| 亚洲精品无播放器在线播放| 日韩久久99| 欧美国产日韩电影| 国产成人a视频高清在线观看| av综合电影网站| 亚洲一区免费| 久久久久亚洲精品中文字幕| 欧美精品资源| 少妇高潮一区二区三区99| 国产精品mv在线观看| 天堂av在线| 午夜性色一区二区三区免费视频| 国产欧美午夜| 97国产精品| 亚洲精品日韩久久| 久久精品国产在热久久| 久久精品国产68国产精品亚洲| 亚洲精品欧美| 国产精品国码视频| 亚洲二区在线| 久久影视三级福利片| 久久av一区| 亚洲成人一区在线观看| 日韩高清欧美激情| jiujiure精品视频播放| 精品一区二区三区中文字幕视频 | 日本午夜免费一区二区| 欧美日中文字幕| 另类国产ts人妖高潮视频| 国产一区2区| 欧美日本精品| 亚洲欧美日本国产| 美女久久一区| 亚洲国产专区校园欧美| 国产在线看片免费视频在线观看| 日韩1区2区日韩1区2区| 免费中文字幕日韩欧美| 激情欧美一区| 日韩欧美自拍| 成人免费电影网址| 久久97久久97精品免视看秋霞| 最新日韩欧美| 伊人久久亚洲影院| 国精品一区二区三区| 欧美日韩色图| 久久久久网站| 精品欧美久久| 欧美日韩国产综合网| 午夜欧美精品| 国产农村妇女精品一二区| 伊人久久亚洲热| 亚洲精品99| 日韩一区精品视频| 免费观看在线综合色| 久久都是精品| 特黄毛片在线观看| 日本中文字幕不卡| 91精品国产经典在线观看| 亚洲精品在线国产| 国产精品亚洲欧美一级在线| 国产欧美久久一区二区三区| 国产精品三级| 肉色欧美久久久久久久免费看| 色婷婷精品视频| 久久先锋影音| 国产欧美丝祙| 正在播放日韩精品| 91久久中文| 国产精品日韩精品中文字幕| 精品伊人久久久| 女人天堂亚洲aⅴ在线观看| 国产99精品一区| 日韩一区精品| 国产高潮在线| 中文字幕中文字幕精品| 成人在线视频中文字幕| 免费观看不卡av| 欧美一级二级视频| 久久国产直播| 人人爱人人干婷婷丁香亚洲| 国产成人精品一区二区免费看京| 亚洲高清久久| 欧美国产先锋| 99在线精品视频在线观看| 国产精品www994| 日韩二区三区四区| 久久亚洲资源中文字| 羞羞答答国产精品www一本| 国产精品99精品一区二区三区∴ | 色88888久久久久久影院| 国产亚洲毛片| 亚洲91视频| 欧美国产极品| 中文不卡在线| 欧美亚洲国产精品久久| 精品资源在线| 欧美日韩午夜电影网| 日本韩国欧美超级黄在线观看| 国产精品主播在线观看| 久久国产精品久久w女人spa| 日韩理论视频| 国产精品久久久久久久久久10秀| 日韩二区三区在线观看| 日韩午夜免费| 午夜精品网站| 国产麻豆久久| 日韩伦理福利| 综合日韩av| 亚洲日本网址| a日韩av网址| 黑人精品一区| 久久国产免费| 亚洲精品成人图区| 久久精品青草| 亚洲成人精品| 今天的高清视频免费播放成人| 日韩视频网站在线观看| 国产成人久久精品麻豆二区 | 亚洲精品2区| 91国语精品自产拍| 免费视频亚洲| 日韩在线一区二区| 视频一区国产视频|