自定义指令

除了 Vue 内置的指令(如 v-if、v-for、v-bind),你还可以注册自定义指令。自定义指令主要用于对 DOM 元素进行底层操作,当内置指令无法满足需求时,自定义指令是很好的选择。

为什么需要自定义指令

虽然 Vue 推荐使用组件和数据驱动视图,但有些场景需要直接操作 DOM:

  • 输入框自动聚焦
  • 权限控制(隐藏/显示元素)
  • 图片懒加载
  • 防抖/节流
  • 复制文本到剪贴板
  • 拖拽功能

这些功能如果封装成组件会显得过于复杂,用自定义指令更简洁。

基本示例

<div id="app">
  <input v-focus placeholder="自动聚焦">
</div>

<script>
Vue.directive('focus', {
  inserted: function(el) {
    el.focus()
  }
})

new Vue({
  el: '#app'
})
</script>

页面加载后,输入框会自动获得焦点。

注册方式

全局注册

Vue.directive('my-directive', {
  bind: function(el, binding, vnode) {
    // 指令绑定到元素时调用
  },
  inserted: function(el, binding, vnode) {
    // 元素插入父节点时调用
  },
  update: function(el, binding, vnode, oldVnode) {
    // VNode 更新时调用
  },
  componentUpdated: function(el, binding, vnode, oldVnode) {
    // VNode 及其子 VNode 全部更新后调用
  },
  unbind: function(el, binding, vnode) {
    // 指令与元素解绑时调用
  }
})

局部注册

new Vue({
  el: '#app',
  directives: {
    'my-directive': {
      bind: function(el, binding) {
        // ...
      }
    }
  }
})

函数简写

如果只需要在 bind 和 update 时执行相同逻辑:

Vue.directive('color', function(el, binding) {
  el.style.color = binding.value
})

本章内容

  • 指令注册:全局注册和局部注册的详细说明
  • 钩子函数:理解每个钩子函数的调用时机
  • 钩子参数:掌握 binding 对象的所有属性
  • 指令示例:实用的自定义指令案例

指令命名规范

// 注册时使用短横线命名
Vue.directive('my-directive', { /* ... */ })

// 使用时
<div v-my-directive></div>

动态指令参数

Vue 2.6+ 支持动态指令参数:

<div v-mydirective:[argument]="value"></div>

<script>
Vue.directive('mydirective', {
  bind: function(el, binding) {
    console.log(binding.arg)    // 参数名
    console.log(binding.value)  // 参数值
  }
})

new Vue({
  el: '#app',
  data: {
    argument: 'direction',
    value: 'top'
  }
})
</script>

指令与组件的选择

何时使用指令:

  • 需要直接操作 DOM
  • 功能简单,不需要模板
  • 可以应用到任意元素

何时使用组件:

  • 需要模板和样式
  • 功能复杂,有状态管理
  • 需要复用整个 UI 结构

学习建议

  1. 从简单的指令开始,如 v-focus、v-color
  2. 理解钩子函数的调用时机
  3. 多看优秀的指令库源码,如 vue-directive-toolkit
  4. 注意指令的性能影响,避免频繁操作 DOM