Vue内置指令与自定义指令

一、Vue 内置指令大全

1. v-bind:动态绑定属性

用于动态绑定 HTML 属性或组件 prop。

html 复制代码
<!-- 绑定 class -->
<div v-bind:class="{ active: isActive }"></div>

<!-- 缩写 -->
<img :src="imageURL" :alt="title">

<!-- 绑定对象 -->
<a v-bind="{ href, target, rel }">链接</a>

✅ 支持所有 HTML 属性和组件 prop。


2. v-model:双向数据绑定

简化表单元素与数据的同步。

html 复制代码
<input v-model="message" placeholder="双向绑定">
<p>输入内容:{{ message }}</p>

<!-- 修饰符 -->
<input v-model.trim="username" />
<input v-model.number="age" />
<input v-model.lazy="search" />

🔁 v-model:value + @input 的语法糖。


3. v-on:事件监听

绑定 DOM 事件。

html 复制代码
<button v-on:click="handleClick">点击</button>
<!-- 缩写 -->
<button @click="save">保存</button>

<!-- 修饰符 -->
<form @submit.prevent="onSubmit">
<input @keyup.enter="search" />
<button @click.once="doOnce">只触发一次</button>

✅ 常用修饰符:.prevent, .stop, .once, .self, .enter, .tab 等。


4. v-if / v-else / v-else-if:条件渲染

根据表达式真假决定是否渲染 DOM。

html 复制代码
<div v-if="type === 'A'">类型 A</div>
<div v-else-if="type === 'B'">类型 B</div>
<div v-else>其他</div>

⚠️ 与 v-show 区别:v-if 是"真正"渲染/销毁,v-showdisplay: none 控制。


5. v-show:显示/隐藏切换

通过 CSS 控制显示状态。

html 复制代码
<div v-show="isVisible">我被 v-show 控制</div>

✅ 适用于频繁切换的场景。


6. v-for:列表渲染

基于数组或对象渲染列表。

html 复制代码
<li v-for="(item, index) in items" :key="item.id">
  {{ index }} - {{ item.name }}
</li>

<!-- 遍历对象 -->
<li v-for="(value, key) in user" :key="key">
  {{ key }}: {{ value }}
</li>

✅ 必须使用 :key 提升性能与稳定性。


7. v-cloak:防止闪现

解决页面加载时 Vue 未初始化导致的 {``{ message }} 闪现问题。

html 复制代码
<style>
  [v-cloak] { display: none; }
</style>

<div v-cloak>{{ message }}</div>

✅ 配合 CSS 使用,Vue 实例挂载后自动移除。


8. v-prev-once

  • v-pre:跳过该元素及其子元素的编译过程。
  • v-once:仅渲染一次,后续更新不重新渲染。
html 复制代码
<span v-pre>{{ this will not be compiled }}</span>
<span v-once>{{ msg }}</span> <!-- msg 变化也不会更新 -->

✅ 用于静态内容或性能优化。

二、自定义指令:扩展 Vue 能力

当内置指令无法满足需求时,我们可以创建自定义指令

1. 注册方式

全局注册
javascript 复制代码
// main.js
import { createApp } from 'vue'
const app = createApp({})

app.directive('focus', {
  mounted(el) {
    el.focus()
  }
})
局部注册
html 复制代码
<script>
export default {
  directives: {
    focus: {
      mounted(el) {
        el.focus()
      }
    }
  }
}
</script>

2. 钩子函数(生命周期)

钩子 触发时机
created 指令绑定前
beforeMount 元素挂载前
mounted 元素插入父节点后(常用)
beforeUpdate 组件更新前
updated 组件更新后
beforeUnmount 元素卸载前
unmounted 元素卸载后(清理事件监听)

3. 钩子函数参数

每个钩子接收以下参数:

javascript 复制代码
app.directive('demo', {
  mounted(el, binding, vnode, prevVnode) {
    // el: 指令绑定的元素
    // binding: 指令信息对象
    //   binding.value: 传入的值
    //   binding.arg: 参数,如 v-demo:arg
    //   binding.modifiers: 修饰符,如 v-demo.foo.bar
    // vnode: 虚拟节点
    // prevVnode: 上一个虚拟节点(更新时)
  }
})

三、自定义指令实战案例

案例 1:自动聚焦(v-focus)

javascript 复制代码
app.directive('focus', {
  mounted(el) {
    el.focus()
  }
})
html 复制代码
<input v-focus placeholder="页面加载后自动聚焦">

案例 2:权限控制(v-permission)

javascript 复制代码
// 假设用户权限存储在全局 store 或 config 中
const userPermissions = ['create', 'edit']

app.directive('permission', {
  mounted(el, binding) {
    const requiredPerm = binding.value
    if (!userPermissions.includes(requiredPerm)) {
      el.parentNode.removeChild(el) // 移除无权限的按钮
      // 或 el.style.display = 'none'
    }
  }
})
html 复制代码
<button v-permission="'create'">新建用户</button>
<button v-permission="'delete'">删除用户</button> <!-- 会被移除 -->

✅ 企业级应用中常见需求。


案例 3:防重复点击(v-debounce)

javascript 复制代码
let timer = null

app.directive('debounce', {
  mounted(el, binding) {
    const delay = binding.value || 1000
    el.addEventListener('click', () => {
      if (timer) return
      binding.instance[binding.arg] && binding.instance[binding.arg]()
      timer = setTimeout(() => {
        timer = null
      }, delay)
    })
  }
})
html 复制代码
<template>
  <button v-debounce:submit="1000">提交</button>
</template>

<script>
export default {
  methods: {
    submit() {
      console.log('表单提交')
      // 发送请求
    }
  }
}
</script>

✅ 防止用户多次点击造成重复提交。


案例 4:图片懒加载(v-lazy)

javascript 复制代码
const imgObserver = new IntersectionObserver((entries) => {
  entries.forEach(entry => {
    if (entry.isIntersecting) {
      const img = entry.target
      img.src = img.dataset.src
      imgObserver.unobserve(img)
    }
  })
})

app.directive('lazy', {
  mounted(el, binding) {
    el.dataset.src = binding.value
    el.src = 'placeholder.jpg' // 占位图
    imgObserver.observe(el)
  },
  unmounted(el) {
    imgObserver.unobserve(el)
  }
})
html 复制代码
<img v-lazy="imageUrl" alt="懒加载图片">

✅ 提升首屏加载性能。

四、Vue 3 Composition API 中的指令

setup() 中注册局部指令:

html 复制代码
<script>
import { ref } from 'vue'

export default {
  setup() {
    const vFocus = {
      mounted: (el) => el.focus()
    }

    const count = ref(0)

    return {
      vFocus,
      count
    }
  }
}
</script>

<template>
  <input v-focus>
</template>

五、最佳实践与注意事项

✅ 推荐做法

  1. 优先使用组件而非指令:指令应专注于 DOM 操作。
  2. 复杂逻辑封装为 composables:避免指令过于臃肿。
  3. 及时清理资源 :在 unmounted 中移除事件监听、定时器等。
  4. 命名语义化 :如 v-permission, v-debounce-click

❌ 避免

  • 在指令中修改组件状态(binding.instance 不稳定)
  • 过度使用全局指令,造成命名污染
  • 忽略响应式更新(updated 钩子)

六、总结

类型 指令 用途
内置指令 v-bind, v-model, v-on 数据绑定与事件
v-if, v-show 条件渲染
v-for 列表渲染
v-cloak, v-pre 编译控制
自定义指令 v-focus, v-permission 扩展 DOM 能力
v-debounce, v-lazy 复用交互逻辑

📌 核心思想:内置指令解决通用问题,自定义指令解决特定场景的 DOM 操作。

七、结语

感谢您的阅读!如果你有任何疑问或想要分享的经验,请在评论区留言交流!

相关推荐
昔人'4 小时前
使用css `focus-visible` 改善用户体验
前端·css·ux
前端双越老师4 小时前
译: 构建高效 AI Agent 智能体
前端·node.js·agent
艾小码4 小时前
告别数据混乱!掌握JSON与内置对象,让你的JS代码更专业
前端·javascript
liangshanbo121510 小时前
写好 React useEffect 的终极指南
前端·javascript·react.js
哆啦A梦158812 小时前
搜索页面布局
前端·vue.js·node.js
_院长大人_12 小时前
el-table-column show-overflow-tooltip 只能显示纯文本,无法渲染 <p> 标签
前端·javascript·vue.js
SevgiliD12 小时前
el-table中控制单列内容多行超出省略及tooltip
javascript·vue.js·elementui