Vue2?模版指令元素綁定事件執(zhí)行順序解析
Vue 自定義指令的執(zhí)行機(jī)制
version: 2.6.14
前情提要
某日,業(yè)務(wù)需要我需要在按鈕點(diǎn)擊之前驗(yàn)證某些條件,如果不符合即不執(zhí)行click內(nèi)的業(yè)務(wù)代碼。思前想后,寫一個(gè)指令不就可以了。做到既不改動(dòng)原有的業(yè)務(wù)代碼,又可以移植。
<template> <button v-capture @click="handleClick">button</button> </template> <script> export default { methods: { handleClick(){ console.log(1) } }, directives: { capture: { bind(el) { el.captureHandler = (e) => { // 驗(yàn)證條件 console.log(2) e.stopPropagation() }; el.addEventListener("click", el.captureHandler); }, unbind(el) { el.removeEventListener("click", el.captureHandler); } } } } </script>
以上就是偽代碼,乍一看沒啥問題。
實(shí)際一運(yùn)行,發(fā)現(xiàn)1和2都打印出來了,而且1還是在2之前運(yùn)行的。
這樣一看模版上綁定的事件執(zhí)行是在自定義指令綁定事件之前的。
翻開谷歌,也沒有找到相關(guān)案例。
DOM綁定
我們都知道vue的SFC最終還是會(huì)被編譯成js文件,最終模板會(huì)被編譯成vnode,
元素上綁定的事件會(huì)轉(zhuǎn)換成vnode上的一個(gè)對(duì)象
{ // .... on: { click: 'handleClick' } }
源碼
那就找一找這個(gè)對(duì)象在哪邊使用的
runtime中搜索addEventListener
, 因?yàn)檫@個(gè)事件綁定上DOM中才有的事件,所以只會(huì)在web中了
// src/platforms/web/runtime/modules/events.js export default { create: updateDOMListeners, update: updateDOMListeners, destroy: (vnode: VNodeWithData) => updateDOMListeners(vnode, emptyNode) }
具體實(shí)現(xiàn)就先不管
updateDOMListeners
中通過調(diào)用了updateListeners
方法,把事件綁定到元素上去
還有就是返回了一個(gè)對(duì)象,包括create、update、destroy, 這不是很像vue的生命周期函數(shù)命名嘛
根據(jù)文件依次向上找??
最終在modules/index.js
中導(dǎo)出了
export default [ attrs, klass, events, domProps, style, transition ]
modules
最終在哪里使用的?
就是大名鼎鼎的patch.js
// src/core/vdom/patch.js const { modules, nodeOps } = backend for (i = 0; i < hooks.length; ++i) { cbs[hooks[i]] = [] for (j = 0; j < modules.length; ++j) { if (isDef(modules[j][hooks[i]])) { cbs[hooks[i]].push(modules[j][hooks[i]]) } } }
函數(shù)一上來就把modules進(jìn)行分類,把原來modules上的相關(guān)的對(duì)象進(jìn)行合并,
最終cbs會(huì)變成一個(gè)對(duì)象
const cbs = { create: [fn1, fn2, fn3], update: [fn1, fn2, fn3], destroy: [fn1, fn2, fn3], }
具體的執(zhí)行的時(shí)機(jī)就不說了
directive
指令是vue的一大特色了,源于angularjs中就有指令這個(gè)東西了,vue3中依舊保留了下來
指令中對(duì)應(yīng)以下幾個(gè)方法,也可以說是生命周期了
directives: { name: { bind(){}, insert(){}, inserted(){}, componentUpdated(){}, update(){}, unbind(){}, } }
接下來找找指令是什么時(shí)候初始化的
全局查找directives
, 其實(shí)就這一個(gè)文件,那就是它了
// src/core/vdom/modules/directives.js { create: updateDirectives, update: updateDirectives, destroy: function unbindDirectives (vnode: VNodeWithData) { updateDirectives(vnode, emptyNode) } }
可以明顯看到它也是在create
內(nèi)部周期上調(diào)用了bind
方法了
callHook(dir, 'bind', vnode, oldVnode)
為什么先調(diào)用模版綁定的方法,再調(diào)用指令的方法
回到patch.js
, 可以看到模塊在這里進(jìn)行了合并,把平臺(tái)相關(guān)的模塊放在前面,基礎(chǔ)指令和ref放在后面執(zhí)行了。
同時(shí)官方也進(jìn)行了注釋,先執(zhí)行內(nèi)置的方法再執(zhí)行指令的方法。
// src/platforms/web/runtime/patch.js import baseModules from 'core/vdom/modules/index' import platformModules from 'web/runtime/modules/index' // the directive module should be applied last, after all // built-in modules have been applied. const modules = platformModules.concat(baseModules)
還是注釋沒仔細(xì)看,這個(gè)文件打開過多少次了。??
改了就可以了嗎
依舊不行。
問題就在addEventListener
身上
拋開vue,看demo
const btn = document.querySelector('#btn') btn.addEventListener('click', () => { console.log(1) }) btn.addEventListener('click', () => { console.log(2) })
總結(jié)
HTML 元素重復(fù)綁定同一個(gè)事件,后者并不會(huì)覆蓋前面的,只會(huì)有綁定的先后順序
那之前的問題還能解么
在捕獲階段執(zhí)行事件, 如果不符合條件,則停止事件傳遞。
el.addEventListener("click", el.captureHandler, true);
并且stopImmediatePropagation
還用不了
stopImmediatePropagation可以阻止元素上綁定的其他事件,但是也是按添加順序,阻止之后的事件執(zhí)行
以上就是Vue2 模版指令元素綁定事件執(zhí)行順序解析的詳細(xì)內(nèi)容,更多關(guān)于Vue2 事件執(zhí)行順序的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
- Vue父子模版?zhèn)髦导敖M件傳值的三種方法
- 詳解vue父子模版嵌套案例
- 詳解用vue2.x版本+adminLTE開源框架搭建后臺(tái)應(yīng)用模版
- vue Element-ui input 遠(yuǎn)程搜索與修改建議顯示模版的示例代碼
- VSCode寫vue項(xiàng)目一鍵生成.vue模版,修改定義其他模板的方法
- 詳解如何用VUE寫一個(gè)多用模態(tài)框組件模版
- 詳解vue 模版組件的三種用法
- vue19 組建 Vue.extend component、組件模版、動(dòng)態(tài)組件 的實(shí)例代碼
- Vue 中可以定義組件模版的幾種方式
- 解決vue與node模版引擎的渲染標(biāo)記{{}}(雙花括號(hào))沖突問題
- vue模版編譯詳情
- vue的指令和插值問題匯總
- vue.js模版插值的原理與實(shí)現(xiàn)方法簡(jiǎn)析
相關(guān)文章
讓 babel webpack vue 配置文件支持智能提示的方法
這篇文章主要介紹了讓 babel webpack vue 配置文件支持智能提示的相關(guān)知識(shí),非常不錯(cuò),具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2019-06-06vue?+elementui?項(xiàng)目登錄通過不同賬號(hào)切換側(cè)邊欄菜單的顏色
這篇文章主要介紹了vue?+elementui?項(xiàng)目登錄通過不同賬號(hào)切換側(cè)邊欄菜單的顏色,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友參考下吧2024-01-01vue中g(shù)et請(qǐng)求如何傳遞數(shù)組參數(shù)的方法示例
這篇文章主要介紹了vue中g(shù)et請(qǐng)求如何傳遞數(shù)組參數(shù)的方法示例,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2019-11-11Vue+scss白天和夜間模式切換功能的實(shí)現(xiàn)方法
這篇文章主要介紹了Vue+scss白天和夜間模式切換功能的實(shí)現(xiàn)方法,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2021-01-01vue 組件內(nèi)獲取actions的response方式
今天小編就為大家分享一篇vue 組件內(nèi)獲取actions的response方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧2019-11-11vue項(xiàng)目查看vue版本及cli版本的實(shí)現(xiàn)方式
這篇文章主要介紹了vue項(xiàng)目查看vue版本及cli版本的實(shí)現(xiàn)方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧2020-10-10