自定义指令

有的情况下,你仍然需要对普通 DOM 元素进行底层操作,这时候就会用到自定义指令. 比如图片懒加载,权限校验,自动聚焦等等

自定义指令的格式:

v - 指令 : 参数 =

自定义指令的使用流程

定义指令

  1. 全局注册

// 注册一个全局自定义指令 `v-focus`
Vue.directive('focus', {
  // 当被绑定的元素插入到 DOM 中时……
  inserted: function (el) {
    // 聚焦元素
    el.focus()  // 页面加载完成之后自动让输入框获取到焦点的小功能
  }
})
  1. 局部注册

export default {
  directives:{
    "abc": {
      bind(el, binding) {
        // 绑定指令时的逻辑
        console.log('abc directive bound', el, binding);
      }
    ,}
  },
}

指令的生命周期

钩子函数

触发时机

常见用途

bind

指令第一次绑定到元素

一次性初始化设置

inserted

被绑定元素插入父节点时

Dom相关操作(需要父节点存在时)

update

所在组件VNode更新时

根据变化执行响应式操作

componentUpdated

所在组件及子组件Vnode全部更新后

访问更新后的Dom

unbind

指令于元素解绑时

清零工作

钩子函数的参数

每个钩子函数接收的参数都是一样的

{
  bind(el, binding, vnode) {
    // el:指令绑定的元素
    // binding:包含指令信息的对象
    // vnode:Vue编译生成的虚拟节点
  }
}

binding对象属性:

value:指令的绑定值. 比如 v-abc="abc" ,value的值为abc

oldValue : 指令绑定的前一个值 ( 仅在 update componentUpdated 中可用 )

arg : 传给指令的参数 . 比如 v-abc:apple , arg apple

modifiers : 包含修饰符的对象 , 比如 v-abc.apple.color , modifiers { apple:true,color:true}

expression : 字符串形式的指令表达式 . 比如 "1+1"

高级用法

  1. 动态指令参数

如果我们定义一个pin指令来讲元素固定在距离页面某一距离的位置,这个距离作为传入值对应了y轴距离,那么确定这个元素的位置还需要x轴的值,实际情况中我们大概率不会用具体的值,而是将元素固定在屏幕两侧,那左边还是右边这个条件就可以作为动态指令参数传入

<template>
  <p v-pin:[direction]="200">固定元素位置</p>
</template>

<script>
Vue.directive('pin', {
  bind: function(el, binding) {
    el.style.position = 'fixed'
    const s = binding.arg || 'top'
    el.style[s] = binding.value + 'px'
  }
})

export default {
  data() {
    return {
      direction: 'left'
    }
  }
}
</script>
  1. 权限控制

Vue.directive('permission', {
  inserted(el, binding) {
    const userRoles = ['admin', 'editor']
    const requiredRole = binding.value
    
    if (!userRoles.includes(requiredRole)) {
      el.parentNode.removeChild(el)
    }
  }
})

// 使用:<button v-permission="'admin'">管理员按钮</button>
  1. 输入限制

Vue.directive('input-limit', {
  bind(el, binding) {
    el.addEventListener('input', () => {
      const regex = new RegExp(binding.value.pattern)
      if (!regex.test(el.value)) {
        el.value = el.value.replace(new RegExp(binding.value.replace, 'g'), '')
        el.dispatchEvent(new Event('input'))
      }
    })
  }
})

// 使用:<input v-input-limit="{ pattern: '[0-9]', replace: '[^0-9]' }">

性能优化建议

  1. 避免在 update 钩子中频繁操作DOM

  2. 使用修饰符进行异化处理

  3. 及时在unbind中移除事件监听和定时器

  4. 对于复杂操作优先考虑组件方案

组合式API

const myDirective = {
  mounted(el, binding) {
    // 组合式API逻辑
    const { value, modifiers } = binding
    if (modifiers.animate) {
      el.style.transition = 'all 0.3s'
    }
  },
  updated(el, binding) {
    // 响应式更新处理
  }
}

// 全局注册
app.directive('my-directive', myDirective)


自定义指令
https://halo.jiangling.site/archives/directive
作者
你的降灵
发布于
2025年07月20日
许可协议