电脑知识|欧美黑人一区二区三区|软件|欧美黑人一级爽快片淫片高清|系统|欧美黑人狂野猛交老妇|数据库|服务器|编程开发|网络运营|知识问答|技术教程文章 - 好吧啦网

您的位置:首頁技術文章
文章詳情頁

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

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

當我用純CSS實現這個以后。我開始用JavaScript和樣式類來完善功能。

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

我們先來看看事件委托到底是什么?他們是怎么工作的,怎么去實現這種機制。

好,它解決了什么問題?

我們先看個簡單的例子。

先假設我們有一組按鈕,我一次點擊一個按鈕,然后我希望被點中的狀態設為"active"。再次點擊時取消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>

我可以用一些標準的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"); });}

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

閉包的陷阱

如果你有一定的JavaScript開發經驗,這個問題就很明顯了。

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

第一個循環它指向第一個button,接下來是第二個。但當你點擊時button變量永遠只指向最后一個button元素,問題出在這。

我們需要的是一個穩定的作用域;讓我們重構一下。

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]));}

注* 上面這段代碼結構有點復雜,也可以簡單直接地使用一個閉包,封閉保存當前的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])}

現在它能正常工作了。指向永遠是正確的button

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

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

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

然而,如果我們有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>

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

相對于封閉button變量去存儲當時我們點擊的對象,我們可以使用event對象去獲取當時點擊的對象。

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

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);}

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

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

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

也許還有其他方法。

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

事件的工作原理

當用戶點擊一個元素時,一個事件就會被產生去通知用戶當前的行為。事件在分發派遣時會有三個階段:

捕獲階段: Capturing 觸發階段: Target冒泡階段: Bubbling

這個事件起始從document之前然后一路向下找到當前事件點擊到的對象。當事件達到點擊到的對象之后,它會按原路返回(冒泡過程),直到退出整個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>

當你單擊Button A時,事件經過的路徑會向下面這樣:

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

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

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

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

事件委托代理

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

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

<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>

因為我們知道單擊button元素會冒泡到UL.toolbar元素,讓我們將事件處理放到這里試試。我們需要稍微調整一下:

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");});

這樣我們清理了大量的代碼,再也沒有循環了。注意我們使用了e.target代替了之前的e.currentTarget。這是因為我們在一個不同的層次上面進行了事件偵聽。

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

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

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

原文地址: codepen.io

標簽: JavaScript
相關文章:
主站蜘蛛池模板: 杜康白酒加盟_杜康酒代理_杜康酒招商加盟官网_杜康酒厂加盟总代理—杜康酒神全国运营中心 | 汽车润滑油厂家-机油/润滑油代理-高性能机油-领驰慧润滑科技(河北)有限公司 | 上海噪音治理公司-专业隔音降噪公司-中广通环保 | 论文查重_免费论文查重_知网学术不端论文查重检测系统入口_论文查重软件 | 圆形振动筛_圆筛_旋振筛_三次元振动筛-河南新乡德诚生产厂家 | ORP控制器_ORP电极价格-上优泰百科 | 液压升降平台_剪叉式液压/导轨式升降机_传菜机定做「宁波日腾升降机厂家」 | 冻干机(冷冻干燥机)_小型|实验型|食品真空冷冻干燥机-松源 | 北京发电车出租-发电机租赁公司-柴油发电机厂家 - 北京明旺盛安机电设备有限公司 | 海峰资讯 - 专注装饰公司营销型网站建设和网络营销培训 | 鄂泉泵业官网|(杭州、上海、全国畅销)大流量防汛排涝泵-LW立式排污泵 | 打孔器,打孔钳厂家【温州新星德牌五金工具】| 四川实木门_成都实木门 - 蓬溪聚成门业有限公司 | 济南保安公司加盟挂靠-亮剑国际安保服务集团总部-山东保安公司|济南保安培训学校 | 黄石东方妇产医院_黄石妇科医院哪家好_黄石无痛人流医院 | 布袋除尘器-单机除尘器-脉冲除尘器-泊头市兴天环保设备有限公司 布袋除尘器|除尘器设备|除尘布袋|除尘设备_诺和环保设备 | 深圳宣传片制作_产品视频制作_深圳3D动画制作公司_深圳短视频拍摄-深圳市西典映画传媒有限公司 | 扒渣机厂家_扒渣机价格_矿用扒渣机_铣挖机_撬毛台车_襄阳永力通扒渣机公司 | 工业冷却塔维修厂家_方形不锈钢工业凉水塔维修改造方案-广东康明节能空调有限公司 | 除甲醛公司-甲醛检测-广西雅居环境科技有限公司 | 冷库安装厂家_杭州冷库_保鲜库建设-浙江克冷制冷设备有限公司 | 考勤系统_考勤管理系统_网络考勤软件_政企|集团|工厂复杂考勤工时统计排班管理系统_天时考勤 | 无痕胶_可移胶_无痕双面胶带_可移无痕胶厂家-东莞凯峰 | 净化板-洁净板-净化板价格-净化板生产厂家-山东鸿星新材料科技股份有限公司 | 海鲜池-专注海鲜鱼缸、移动海鲜缸、饭店鱼缸设计定做-日晟水族厂家 | 联系我们-腾龙公司上分客服微信19116098882 | 微水泥_硅藻泥_艺术涂料_艺术漆_艺术漆加盟-青岛泥之韵环保壁材 武汉EPS线条_EPS装饰线条_EPS构件_湖北博欧EPS线条厂家 | 世纪豪门官网 世纪豪门集成吊顶加盟电话 世纪豪门售后电话 | 屏蔽泵厂家,化工屏蔽泵_维修-淄博泵业 | 断桥铝破碎机_铝合金破碎机_废铁金属破碎机-河南鑫世昌机械制造有限公司 | 单柱拉力机-橡胶冲片机-哑铃裁刀-江都轩宇试验机械厂 | 塑胶跑道施工-硅pu篮球场施工-塑胶网球场建造-丙烯酸球场材料厂家-奥茵 | Q361F全焊接球阀,200X减压稳压阀,ZJHP气动单座调节阀-上海戎钛 | 大行程影像测量仪-探针型影像测量仪-增强型影像测量仪|首丰百科 大通天成企业资质代办_承装修试电力设施许可证_增值电信业务经营许可证_无人机运营合格证_广播电视节目制作许可证 | 订做不锈钢_不锈钢定做加工厂_不锈钢非标定制-重庆侨峰金属加工厂 | 单级/双级旋片式真空泵厂家,2xz旋片真空泵-浙江台州求精真空泵有限公司 | 数码管_LED贴片灯_LED数码管厂家-无锡市冠卓电子科技有限公司 | 除甲醛公司-甲醛检测-广西雅居环境科技有限公司 | 天津蒸汽/热水锅炉-电锅炉安装维修直销厂家-天津鑫淼暖通设备有限公司 | 四川成都干燥设备_回转筒干燥机_脉冲除尘器_输送设备_热风炉_成都川工星科机电设备有限公司 | 订做不锈钢_不锈钢定做加工厂_不锈钢非标定制-重庆侨峰金属加工厂 |