Vue2|Vue2 模版指令元素绑定事件执行顺序解析
目录
- Vue 自定义指令的执行机制
- 前情提要
- DOM绑定
- 源码
- directive
- 为什么先调用模版绑定的方法,再调用指令的方法
- 总结
Vue 自定义指令的执行机制
version: 2.6.14
前情提要
某日,业务需要我需要在按钮点击之前验证某些条件,如果不符合即不执行click内的业务代码。思前想后,写一个指令不就可以了。做到既不改动原有的业务代码,又可以移植。
以上就是伪代码,乍一看没啥问题。
实际一运行,发现1和2都打印出来了,而且1还是在2之前运行的。
这样一看模版上绑定的事件执行是在自定义指令绑定事件之前的。
翻开谷歌,也没有找到相关案例。
DOM绑定 我们都知道vue的SFC最终还是会被编译成js文件,最终模板会被编译成vnode,
元素上绑定的事件会转换成vnode上的一个对象
{// ....on: {click: 'handleClick'}}
源码
那就找一找这个对象在哪边使用的
runtime中搜索
addEventListener
, 因为这个事件绑定上DOM中才有的事件,所以只会在web中了// src/platforms/web/runtime/modules/events.jsexport default {create: updateDOMListeners,update: updateDOMListeners,destroy: (vnode: VNodeWithData) => updateDOMListeners(vnode, emptyNode)}
具体实现就先不管
updateDOMListeners
中通过调用了updateListeners
方法,把事件绑定到元素上去还有就是返回了一个对象,包括create、update、destroy, 这不是很像vue的生命周期函数命名嘛
根据文件依次向上找
最终在
modules/index.js
中导出了export default [attrs,klass,events,domProps,style,transition]
modules
最终在哪里使用的?就是大名鼎鼎的
patch.js
// src/core/vdom/patch.jsconst { modules, nodeOps } = backendfor (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]])}}}
函数一上来就把modules进行分类,把原来modules上的相关的对象进行合并,
最终cbs会变成一个对象
const cbs = {create: [fn1, fn2, fn3],update: [fn1, fn2, fn3],destroy: [fn1, fn2, fn3],}
具体的执行的时机就不说了
directive 指令是vue的一大特色了,源于angularjs中就有指令这个东西了,vue3中依旧保留了下来
指令中对应以下几个方法,也可以说是生命周期了
directives: {name: {bind(){},insert(){},inserted(){},componentUpdated(){},update(){},unbind(){},}}
接下来找找指令是什么时候初始化的
全局查找
directives
, 其实就这一个文件,那就是它了// src/core/vdom/modules/directives.js{create: updateDirectives,update: updateDirectives,destroy: function unbindDirectives (vnode: VNodeWithData) {updateDirectives(vnode, emptyNode)}}
可以明显看到它也是在
create
内部周期上调用了bind
方法了callHook(dir, 'bind', vnode, oldVnode)
为什么先调用模版绑定的方法,再调用指令的方法
回到
patch.js
, 可以看到模块在这里进行了合并,把平台相关的模块放在前面,基础指令和ref放在后面执行了。同时官方也进行了注释,先执行内置的方法再执行指令的方法。
// src/platforms/web/runtime/patch.jsimport 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)
还是注释没仔细看,这个文件打开过多少次了。
改了就可以了吗
依旧不行。
问题就在
addEventListener
身上抛开vue,看demo
const btn = document.querySelector('#btn')btn.addEventListener('click', () => {console.log(1)})btn.addEventListener('click', () => {console.log(2)})
总结 HTML 元素重复绑定同一个事件,后者并不会覆盖前面的,只会有绑定的先后顺序
那之前的问题还能解么
在捕获阶段执行事件, 如果不符合条件,则停止事件传递。
el.addEventListener("click", el.captureHandler, true);
并且
stopImmediatePropagation
还用不了stopImmediatePropagation可以阻止元素上绑定的其他事件,但是也是按添加顺序,阻止之后的事件执行
【Vue2|Vue2 模版指令元素绑定事件执行顺序解析】以上就是Vue2 模版指令元素绑定事件执行顺序解析的详细内容,更多关于Vue2 事件执行顺序的资料请关注脚本之家其它相关文章!
推荐阅读
- VUE的JS指令
- Vue2.x与Vue3.x中路由钩子的区别详解
- 【javaWeb微服务架构项目——乐优商城day02】——Vue.js(认识Vue,Node和NPM,Vue实例,指令,组件化,路由vue-router)
- VUE 自定义指令实现点击后禁用elementUI按钮
- vue关于自定义指令与v-if冲突的问题
- vue|Vue2.0+组件库总结
- 盘点Vue2和Vue3的10种组件通信方式(值得收藏)
- elementui|vue2+elTree 实现右键菜单
- Redis常用指令之string、list、set、zset、hash
- VUE中的自定义指令钩子函数讲解