我的编程空间,编程开发者的网络收藏夹
学习永远不晚

Vue3指令是怎么实现的

短信预约 -IT技能 免费直播动态提醒
省份

北京

  • 北京
  • 上海
  • 天津
  • 重庆
  • 河北
  • 山东
  • 辽宁
  • 黑龙江
  • 吉林
  • 甘肃
  • 青海
  • 河南
  • 江苏
  • 湖北
  • 湖南
  • 江西
  • 浙江
  • 广东
  • 云南
  • 福建
  • 海南
  • 山西
  • 四川
  • 陕西
  • 贵州
  • 安徽
  • 广西
  • 内蒙
  • 西藏
  • 新疆
  • 宁夏
  • 兵团
手机号立即预约

请填写图片验证码后获取短信验证码

看不清楚,换张图片

免费获取短信验证码

Vue3指令是怎么实现的

今天小编给大家分享一下Vue3指令是怎么实现的的相关知识点,内容详细,逻辑清晰,相信大部分人都还太了解这方面的知识,所以分享这篇文章给大家参考一下,希望大家阅读完这篇文章后有所收获,下面我们一起来了解一下吧。

    前言

    Vue 指令 是指 对普通DOM元素进行底层操作的JS对象, 它们会被挂在Element VNode对象上,在Element VNode的一些生命周期中会被调用,从而可以操作Element VNode的底层DOM元素。

    指令注册

    指令注册 是指将指令对应的JS代码放置在某些地方,需要使用的时候可以在这些地方进行查找。

    全局注册

    • 全局注册是调用app.directive('指令名称', { 指令代码 }) 来实现的

    app.directive('pin', (el, binding) => {  el.style.position = 'fixed'  const s = binding.arg || 'top'  el.style[s] = binding.value + 'px'})
    • 全局注册的逻辑是将 指令名称 和 对应的指令代码 挂载在全局的context的directives对象上

    <!-- apiCreateApp.js -->directive(name: string, directive?: Directive) {    // 挂载在全局的`context`的`directives`对象上  context.directives[name] = directive    return app},

    组件内注册

    • 组件内注册是在组件内添加 directives 的选项

    directives: {  pin: (el, binding) => {    el.style.position = 'fixed'    const s = binding.arg || 'top'    el.style[s] = binding.value + 'px'  }}
    • 组件注册的逻辑是将 指令名称 和 对应的指令代码 挂载在组件实例对象的directives上

    <!-- component.ts -->export function applyOptions(instance: ComponentInternalInstance) {    // 挂载在组件实例对象的`directives`上      instance.directives = directives  }

    指令搜寻

    指令搜寻的时机

    开发者是在模板中使用指令,所以应该是在模板渲染的时候需要先搜寻到对应的指令。

    不使用指令的模板<h5>指令演示</h5>渲染函数如下:

    function render(_ctx, _cache) {  with (_ctx) {    const { openBlock: _openBlock, createElementBlock: _createElementBlock } = _Vue    return (_openBlock(), _createElementBlock("h5", null, "指令演示"))  }}

    使用指令的模板<h5 v-pin:[right]="20">指令演示</h5>渲染函数如下:

    function render(_ctx, _cache) {  with (_ctx) {    const { createTextVNode: _createTextVNode, resolveDirective: _resolveDirective, withDirectives: _withDirectives, openBlock: _openBlock, createElementBlock: _createElementBlock } = _Vue    const _directive_pin = _resolveDirective("pin")    return _withDirectives((_openBlock(), _createElementBlock("h5", null, _hoisted_2, 512 )), [      [_directive_pin, pinPadding, direction]    ])  }}

    Vue3指令是怎么实现的

    使用指令的模板需要先搜寻对应的指令,然后绑定指令到VNode

    指令搜寻的逻辑

    • 指令搜寻的逻辑是先从组件实例instance的directives上寻找,如果没找到再在appContext的directives上寻找

    export function resolveDirective(name: string): Directive | undefined {  return resolveAsset(DIRECTIVES, name)}function resolveAsset(  type: AssetTypes,  name: string,  warnMissing = true,  maybeSelfReference = false) {    const res =    // local registration    // check instance[type] first which is resolved for options API    resolve(instance[type] || (Component as ComponentOptions)[type], name) ||    // global registration    resolve(instance.appContext[type], name)    return res}

    指令绑定VNode

    export function withDirectives<T extends VNode>(  vnode: T,  directives: DirectiveArguments): T {      const bindings: DirectiveBinding[] = vnode.dirs || (vnode.dirs = [])    for (let i = 0; i < directives.length; i++) {    let [dir, value, arg, modifiers = EMPTY_OBJ] = directives[i]    if (isFunction(dir)) {      dir = {        mounted: dir,        updated: dir      } as ObjectDirective    }    bindings.push({      dir,      instance,      value,      oldValue: void 0,      arg,      modifiers    })  }  return vnode}

    将每个指令dir和其他一些参数 挂载在 VNode的dirs上。 其他参数是: instance组件实例, value指令的新值(本例为20),oldValue指令的旧值(本例为0),arg指令的参数(本例为right)

    指令调用

    指令调用是指 指令的代码什么时候被执行的? 我们最开始提到指令是对普通DOM元素进行底层操作的JS对象,所以指令的逻辑应该是在 Element VNode中进行处理的。

    const mountElement = (  vnode: VNode,  container: RendererElement,  anchor: RendererNode | null,  parentComponent: ComponentInternalInstance | null,  parentSuspense: SuspenseBoundary | null,  isSVG: boolean,  slotScopeIds: string[] | null,  optimized: boolean) => {    // 1    if (dirs) {      invokeDirectiveHook(vnode, null, parentComponent, 'created')    }    // 2    if (dirs) {        invokeDirectiveHook(vnode, null, parentComponent, 'beforeMount')    }        // 3    queuePostRenderEffect(() => {      vnodeHook && invokeVNodeHook(vnodeHook, parentComponent, vnode)      needCallTransitionHooks && transition!.enter(el)      dirs && invokeDirectiveHook(vnode, null, parentComponent, 'mounted')    }, parentSuspense)}
    const patchElement = (  n1: VNode,  n2: VNode,  parentComponent: ComponentInternalInstance | null,  parentSuspense: SuspenseBoundary | null,  isSVG: boolean,  slotScopeIds: string[] | null,  optimized: boolean) => {  const el = (n2.el = n1.el!)    // 1  if (dirs) {    invokeDirectiveHook(n2, n1, parentComponent, 'beforeUpdate')  }  // 2  queuePostRenderEffect(() => {      vnodeHook && invokeVNodeHook(vnodeHook, parentComponent, n2, n1)      dirs && invokeDirectiveHook(n2, n1, parentComponent, 'updated')    }, parentSuspense)}
    const unmount: UnmountFn = (  vnode,  parentComponent,  parentSuspense,  doRemove = false,  optimized = false) => {  const {    type,    props,    ref,    children,    dynamicChildren,    shapeFlag,    patchFlag,    dirs  } = vnode  // unset ref  if (ref != null) {    setRef(ref, null, parentSuspense, vnode, true)  }  if (shapeFlag & ShapeFlags.COMPONENT_SHOULD_KEEP_ALIVE) {    ;(parentComponent!.ctx as KeepAliveContext).deactivate(vnode)    return  }  const shouldInvokeDirs = shapeFlag & ShapeFlags.ELEMENT && dirs  let vnodeHook: VNodeHook | undefined | null  if ((vnodeHook = props && props.onVnodeBeforeUnmount)) {    invokeVNodeHook(vnodeHook, parentComponent, vnode)  }  if (shapeFlag & ShapeFlags.COMPONENT) {    unmountComponent(vnode.component!, parentSuspense, doRemove)  } else {    if (shouldInvokeDirs) {      invokeDirectiveHook(vnode, null, parentComponent, 'beforeUnmount')    }    queuePostRenderEffect(() => {      vnodeHook && invokeVNodeHook(vnodeHook, parentComponent, vnode)      shouldInvokeDirs &&        invokeDirectiveHook(vnode, null, parentComponent, 'unmounted')    }, parentSuspense)}

    在挂载元素VNode的时候,会调用指令的created, beforeMount和mounted钩子函数;

    在更新元素VNode的时候,会调用指令的beforeUpdate, updated钩子函数;

    在卸载元素VNode的时候,会调用指令的beforeUnmount, unmounted钩子函数;

    关于指令的思考

    组件上使用指令

    我们上面提到了指令是作用在元素VNode上的,那组件使用指令(例如<son v-pin:[right]="20"></son>)是什么效果呢?结果是组件上使用的指令会作用在组件内部的根节点的元素VNode上。

    export function renderComponentRoot(  instance: ComponentInternalInstance): VNode {  const {    type: Component,    vnode,    proxy,    withProxy,    props,    propsOptions: [propsOptions],    slots,    attrs,    emit,    render,    renderCache,    data,    setupState,    ctx,    inheritAttrs  } = instance    // inherit directives    if (vnode.dirs) {      if (__DEV__ && !isElementRoot(root)) {        warn(          `Runtime directive used on component with non-element root node. ` +            `The directives will not function as intended.`        )      }      root.dirs = root.dirs ? root.dirs.concat(vnode.dirs) : vnode.dirs    }}

    在组件渲染子树VNode的根VNode时候,会将组件的指令dirs添加在根元素VNode的dirs中。所以作用于组件的指令 等同于 作用于 根节点的元素VNode上。

    组件上的一些使用场景

    我觉得一些比较使用的指令的使用场景有:

    • v-lazyload: 图片的懒加载

    • v-loading:实现加一个加载动画

    • v-permission: 权限控制,没有权限就隐藏DOM元素

    • v-debounce: 输入防抖,特别是搜素框请求的输入

    以上就是“Vue3指令是怎么实现的”这篇文章的所有内容,感谢各位的阅读!相信大家阅读完这篇文章都有很大的收获,小编每天都会为大家更新不同的知识,如果还想学习更多的知识,请关注编程网行业资讯频道。

    免责声明:

    ① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

    ② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

    Vue3指令是怎么实现的

    下载Word文档到电脑,方便收藏和打印~

    下载Word文档

    猜你喜欢

    Vue3指令是怎么实现的

    今天小编给大家分享一下Vue3指令是怎么实现的的相关知识点,内容详细,逻辑清晰,相信大部分人都还太了解这方面的知识,所以分享这篇文章给大家参考一下,希望大家阅读完这篇文章后有所收获,下面我们一起来了解一下吧。前言Vue 指令 是指 对普通D
    2023-06-29

    怎么用Vue3指令实现水印背景

    页面水印业务相信我们都有遇过,为什么需要给页面添加水印?为了保护自己的版权和知识产权,给图片加上水印一般是为了防止盗图者用于商业用途,损害原作者的权益。那么在我们开发当中有什么方法可以实现呢?一般分为前端实现和后端实现这两种方法,本文主要是学习前端实现方法:方式一:直接将字体用块元素包裹,动态设置绝对定位,然后通过transform属性旋转。但是需要考虑一个问题,当图片过大或图片过多时会很影响性能,所以就不详细说这一方式了。方式二:canvas上绘制出字体,设置好样式,最后以图片的样式导出,用图
    2023-05-14

    怎么在Vue3中实现自定义指令

    这篇文章主要介绍“怎么在Vue3中实现自定义指令”,在日常操作中,相信很多人在怎么在Vue3中实现自定义指令问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”怎么在Vue3中实现自定义指令”的疑惑有所帮助!接下来
    2023-07-02

    vue3+ts+elementPLus实现v-preview指令

    本文主要介绍了vue3+ts+elementPLus实现v-preview指令,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2023-05-20

    vue3中怎么自定义指令实现按钮防抖

    这篇“vue3中怎么自定义指令实现按钮防抖”文章的知识点大部分人都不太理解,所以小编给大家总结了以下内容,内容详细,步骤清晰,具有一定的借鉴价值,希望大家阅读完这篇文章能有所收获,下面我们一起来看看这篇“vue3中怎么自定义指令实现按钮防抖
    2023-07-05

    vue3自定义指令的方法是什么

    这篇文章主要介绍“vue3自定义指令的方法是什么”,在日常操作中,相信很多人在vue3自定义指令的方法是什么问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”vue3自定义指令的方法是什么”的疑惑有所帮助!接下来
    2023-07-04

    vue3自定义指令方法是什么

    这篇文章主要讲解了“vue3自定义指令方法是什么”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“vue3自定义指令方法是什么”吧!一、注册自定义指令以下实例都是实现一个输入框自动获取焦点的自定
    2023-06-21

    如何用Vue3指令实现水印背景

    这篇文章主要介绍了如何用Vue3指令实现水印背景的相关知识,内容详细易懂,操作简单快捷,具有一定借鉴价值,相信大家阅读完这篇如何用Vue3指令实现水印背景文章都会有所收获,下面我们一起来看看吧。首先定义一个指令,我们要明确两点:命名(v-w
    2023-07-06

    怎么写一个Vue3的自定义指令

    本篇内容主要讲解“怎么写一个Vue3的自定义指令”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“怎么写一个Vue3的自定义指令”吧!背景众所周知,Vue.js 的核心思想是数据驱动 + 组件化,通
    2023-06-26

    Vue3计算属性是怎么实现的

    今天小编给大家分享一下Vue3计算属性是怎么实现的的相关知识点,内容详细,逻辑清晰,相信大部分人都还太了解这方面的知识,所以分享这篇文章给大家参考一下,希望大家阅读完这篇文章后有所收获,下面我们一起来了解一下吧。计算属性是 Vue.js 开
    2023-06-30

    Vue3怎么编写自定义指令插件

    今天小编给大家分享一下Vue3怎么编写自定义指令插件的相关知识点,内容详细,逻辑清晰,相信大部分人都还太了解这方面的知识,所以分享这篇文章给大家参考一下,希望大家阅读完这篇文章后有所收获,下面我们一起来了解一下吧。编写自定义插件// src
    2023-07-02

    Vue3中的setup与自定义指令怎么使用

    setup语法糖最大好处就是所有声明部分皆可直接使用,无需return出去注意:部分功能还不完善,如:name、render还需要单独加入script标签按compositionAPI方式编写//setup下还可以附加setup语法糖独有import{ref,reactive,toRefs}from&#39;vue&#39;consta=1;constnum=ref(99)//基本数据类型constuser=reactive({//引用数据类型age:11})//解构能获取响应式
    2023-05-14

    Vue3指令之搜索框输入防抖功能实现

    在Vue开发中遇到了搜索框输入防抖处理,算是防抖的使用场景之一吧,这篇文章主要给大家介绍了关于Vue3指令之搜索框输入防抖功能实现的相关资料,需要的朋友可以参考下
    2022-12-29

    vue2怎么实现vue3的teleport

    本篇内容主要讲解“vue2怎么实现vue3的teleport”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“vue2怎么实现vue3的teleport”吧!vue2实现vue3的teleport不
    2023-06-30

    Vue3中的模板语法和vue指令怎么使用

    1模板插值语法在script声明一个变量可以直接在template使用用法为{{变量名称}}模板语法是可以编写条件运算的运算也是支持的操作API也是支持的{{message}}{{message2==0?&#39;我是老大&#39;:&#39;我笑的&#39;}}{{message2+1}}{{message.split(&#39;&#39;).map(v=>`4546$v`)}}constmessage="我是唐少"co
    2023-05-18

    Vue中的自定义指令怎么实现

    今天小编给大家分享一下Vue中的自定义指令怎么实现的相关知识点,内容详细,逻辑清晰,相信大部分人都还太了解这方面的知识,所以分享这篇文章给大家参考一下,希望大家阅读完这篇文章后有所收获,下面我们一起来了解一下吧。试炼:实现v-mymodel
    2023-07-04

    编程热搜

    • Python 学习之路 - Python
      一、安装Python34Windows在Python官网(https://www.python.org/downloads/)下载安装包并安装。Python的默认安装路径是:C:\Python34配置环境变量:【右键计算机】--》【属性】-
      Python 学习之路 - Python
    • chatgpt的中文全称是什么
      chatgpt的中文全称是生成型预训练变换模型。ChatGPT是什么ChatGPT是美国人工智能研究实验室OpenAI开发的一种全新聊天机器人模型,它能够通过学习和理解人类的语言来进行对话,还能根据聊天的上下文进行互动,并协助人类完成一系列
      chatgpt的中文全称是什么
    • C/C++中extern函数使用详解
    • C/C++可变参数的使用
      可变参数的使用方法远远不止以下几种,不过在C,C++中使用可变参数时要小心,在使用printf()等函数时传入的参数个数一定不能比前面的格式化字符串中的’%’符号个数少,否则会产生访问越界,运气不好的话还会导致程序崩溃
      C/C++可变参数的使用
    • css样式文件该放在哪里
    • php中数组下标必须是连续的吗
    • Python 3 教程
      Python 3 教程 Python 的 3.0 版本,常被称为 Python 3000,或简称 Py3k。相对于 Python 的早期版本,这是一个较大的升级。为了不带入过多的累赘,Python 3.0 在设计的时候没有考虑向下兼容。 Python
      Python 3 教程
    • Python pip包管理
      一、前言    在Python中, 安装第三方模块是通过 setuptools 这个工具完成的。 Python有两个封装了 setuptools的包管理工具: easy_install  和  pip , 目前官方推荐使用 pip。    
      Python pip包管理
    • ubuntu如何重新编译内核
    • 改善Java代码之慎用java动态编译

    目录