vue2 和 vue3自定义指令有什么区别,都是怎么实现和使用一个指令

Vue 2 和 Vue 3 自定义指令的区别(面试高频必问,基于官方迁移指南 + Vue 3.4+ 最新文档)

1. 最核心区别总结(30秒回答版)

维度Vue 2(Options API 时代)Vue 3(Composition API + 新指令 API)影响
钩子函数命名bindinsertedupdatecomponentUpdatedunbind重命名并对齐组件生命周期
created(新增)
beforeMount(=bind)
mounted(=inserted)
beforeUpdate(新增)
updated(=componentUpdated)
beforeUnmount(新增)
unmounted(=unbind)
Vue 3 更统一、更易记
移除的钩子update(被认为是冗余)彻底移除,用 updated 替代减少重复代码
binding 对象binding.expression(字符串表达式)移除 expression,统一用 binding.value迁移时最容易踩坑
注册方式Vue.directive()(全局)
directives: {}(局部)
app.directive()(全局)
directives: {}<script setup>const vXXX = {}(局部)
Vue 3 更模块化
简化写法较少支持支持函数简写(同时作用于 mounted + updated)常用场景更简洁
其他支持 vnode.context 获取实例binding.instance 获取实例;支持 Fragment,但多根组件上指令会警告Vue 3 更现代

一句话总结:Vue 3 把指令钩子彻底对齐组件生命周期,去掉了冗余钩子,简化了 binding 对象,让代码更清晰、更容易维护。

2. 如何实现和使用一个指令(以最经典的 v-focus 自动聚焦为例)

Vue 2 写法

// 1. 全局注册(main.js)
Vue.directive('focus', {
  inserted(el) {        // 最常用钩子:元素插入 DOM 后
    el.focus()
  }
})

// 2. 局部注册(组件内)
export default {
  directives: {
    focus: {
      inserted(el) {
        el.focus()
      }
    }
  }
}

使用:

<input v-focus />

Vue 3 写法(推荐方式)

<!-- 方式一:在 <script setup> 中直接定义(最推荐,Vue 3.2+) -->
<script setup>
const vFocus = {
  mounted(el) {     // 对应 Vue 2 的 inserted
    el.focus()
  }
}
</script>

<template>
  <input v-focus />
</template>
// 方式二:全局注册(main.js / main.ts)
import { createApp } from 'vue'
const app = createApp(App)

app.directive('focus', {
  mounted(el) {
    el.focus()
  }
})
// 方式三:局部注册(Options API 风格组件)
export default {
  directives: {
    focus: {
      mounted(el) {
        el.focus()
      }
    }
  }
}

函数简写(当只需要 mounted + updated 时,超级简洁):

// 全局
app.directive('color', (el, binding) => {
  el.style.color = binding.value   // 同时在 mounted 和 updated 时执行
})

// 使用
<div v-color="textColor"></div>

3. 完整钩子对比 + 参数说明(面试手画表格必备)

每个钩子都接收 4 个参数(Vue 3):

(el, binding, vnode, prevVnode) => {}
  • el:真实 DOM 元素(可直接操作样式、事件、class)
  • binding:核心对象
  • value:传给指令的值(v-my-dir="123" → 123)
  • oldValue:旧值(仅 beforeUpdate / updated 有)
  • arg:参数(v-my-dir:arg 中的 arg)
  • modifiers:修饰符对象(v-my-dir.mod1.mod2{ mod1: true, mod2: true }
  • instance:组件实例(Vue 3 新增)
  • vnode / prevVnode:虚拟节点

4. 实战示例:v-debounce(防抖点击指令)(面试加分题)

Vue 3 完整实现(同时展示函数简写和对象写法):

<script setup>
const vDebounce = {
  mounted(el, binding) {
    let timer = null
    el.addEventListener('click', () => {
      if (timer) clearTimeout(timer)
      timer = setTimeout(() => {
        binding.value()   // 执行传入的函数
      }, 500)
    })
  }
}
</script>

<template>
  <button v-debounce="handleClick">防抖按钮</button>
</template>

5. 迁移建议(从 Vue 2 升级时)

  • bind 改成 beforeMount
  • inserted 改成 mounted
  • componentUpdated 改成 updated
  • 删除所有 update 钩子
  • binding.expression 全部换成 binding.value
  • 全局注册从 Vue.directive 改成 app.directive

掌握上面这套内容,面试官问“自定义指令区别”基本稳了!

需要我再给你:

  • 防抖 + 节流完整对比代码
  • v-lazy(图片懒加载)实战
  • Vue 3 + TypeScript 写指令的写法
  • 面试追问 10 题(为什么移除 update?binding.expression 为什么删?)

随时说~ 这块知识点背熟后,Vue 进阶题基本无敌!🚀

文章已创建 5041

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

相关文章

开始在上面输入您的搜索词,然后按回车进行搜索。按ESC取消。

返回顶部