Vue2 模版指令元素绑定事件执行顺序解析

 更新时间:2022年08月26日 11:58:29   作者:JunIce  
这篇文章主要为大家介绍了Vue2 模版指令元素绑定事件执行顺序解析,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪

Vue 自定义指令的执行机制

version: 2.6.14

前情提要

某日,业务需要我需要在按钮点击之前验证某些条件,如果不符合即不执行click内的业务代码。思前想后,写一个指令不就可以了。做到既不改动原有的业务代码,又可以移植。

<template>
  <button v-capture @click="handleClick">button</button>
</template>
<script>
  export default {
    methods: {
      handleClick(){
        console.log(1)
      }
    },
    directives: {
      capture: {
        bind(el) {
          el.captureHandler = (e) => {
            // 验证条件
            console.log(2)
            e.stopPropagation()
          };
          el.addEventListener("click", el.captureHandler);
        },
        unbind(el) {
          el.removeEventListener("click", el.captureHandler);
        }
      }
    }
}
</script>

以上就是伪代码,乍一看没啥问题。

实际一运行,发现1和2都打印出来了,而且1还是在2之前运行的。

这样一看模版上绑定的事件执行是在自定义指令绑定事件之前的。

翻开谷歌,也没有找到相关案例。

DOM绑定

我们都知道vue的SFC最终还是会被编译成js文件,最终模板会被编译成vnode,

元素上绑定的事件会转换成vnode上的一个对象

{
  // ....
  on: {
    click: 'handleClick'
  }
}

源码

那就找一找这个对象在哪边使用的

runtime中搜索addEventListener, 因为这个事件绑定上DOM中才有的事件,所以只会在web中了

// src/platforms/web/runtime/modules/events.js
export 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.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]])
    }
  }
}

函数一上来就把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.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)

还是注释没仔细看,这个文件打开过多少次了。😭

改了就可以了吗

依旧不行。

问题就在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 事件执行顺序的资料请关注脚本之家其它相关文章!

相关文章

  • 让 babel webpack vue 配置文件支持智能提示的方法

    让 babel webpack vue 配置文件支持智能提示的方法

    这篇文章主要介绍了让 babel webpack vue 配置文件支持智能提示的相关知识,非常不错,具有一定的参考借鉴价值,需要的朋友可以参考下
    2019-06-06
  • vue +elementui 项目登录通过不同账号切换侧边栏菜单的颜色

    vue +elementui 项目登录通过不同账号切换侧边栏菜单的颜色

    这篇文章主要介绍了vue +elementui 项目登录通过不同账号切换侧边栏菜单的颜色,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友参考下吧
    2024-01-01
  • Vue组件上使用v-model之单选框

    Vue组件上使用v-model之单选框

    这篇文章主要介绍了Vue组件上使用v-model之单选框,代码分为子组件内容和父组件内容,本文结合实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2022-10-10
  • vue中get请求如何传递数组参数的方法示例

    vue中get请求如何传递数组参数的方法示例

    这篇文章主要介绍了vue中get请求如何传递数组参数的方法示例,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2019-11-11
  • Vue+scss白天和夜间模式切换功能的实现方法

    Vue+scss白天和夜间模式切换功能的实现方法

    这篇文章主要介绍了Vue+scss白天和夜间模式切换功能的实现方法,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2021-01-01
  • vue 组件内获取actions的response方式

    vue 组件内获取actions的response方式

    今天小编就为大家分享一篇vue 组件内获取actions的response方式,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2019-11-11
  • vue项目查看vue版本及cli版本的实现方式

    vue项目查看vue版本及cli版本的实现方式

    这篇文章主要介绍了vue项目查看vue版本及cli版本的实现方式,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2020-10-10
  • 使用Vant如何完成各种Toast提示框

    使用Vant如何完成各种Toast提示框

    这篇文章主要介绍了使用Vant如何完成各种Toast提示框,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2022-05-05
  • 关于vue编译版本引入的问题的解决

    关于vue编译版本引入的问题的解决

    这篇文章主要介绍了关于vue编译版本引入的问题的解决,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2018-09-09
  • vue如何使用AIlabel标注组件

    vue如何使用AIlabel标注组件

    这篇文章主要介绍了vue如何使用AIlabel标注组件,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2022-04-04

最新评论