vue3中自定义指令使用

Vue 3 自定义指令详细使用指南

1. 基本结构

一个完整的自定义指令包含以下可选钩子函数:

javascript 复制代码
const myDirective = {
  // 指令第一次绑定到元素时调用(只调用一次)
  created(el, binding, vnode, prevVnode) {},
  
  // 元素插入父 DOM 前调用
  beforeMount(el, binding, vnode, prevVnode) {},
  
  // 元素插入父 DOM 后调用
  mounted(el, binding, vnode, prevVnode) {},
  
  // 父组件更新前调用
  beforeUpdate(el, binding, vnode, prevVnode) {},
  
  // 父组件和子组件都更新后调用
  updated(el, binding, vnode, prevVnode) {},
  
  // 父组件卸载前调用
  beforeUnmount(el, binding, vnode, prevVnode) {},
  
  // 父组件卸载后调用
  unmounted(el, binding, vnode, prevVnode) {}
}

2.钩子函数参数

3.注册方式

3.1全局注册

javascript 复制代码
// main.js
import { createApp } from 'vue'
import App from './App.vue'

const app = createApp(App)

app.directive('focus', {
  mounted(el) {
    el.focus()
  }
})

app.mount('#app')

3.2 局部注册

javascript 复制代码
// 在组件中
export default {
  directives: {
    focus: {
      mounted(el) {
        el.focus()
      }
    }
  }
}

4.使用方式

5.实用示例

5.1权限控制指令

javascript 复制代码
app.directive('permission', {
  mounted(el, binding) {
    const userPermissions = ['edit', 'view'] // 通常从store获取
    if (!userPermissions.includes(binding.value)) {
      el.style.display = 'none'
      // 或者直接移除元素
      // el.parentNode.removeChild(el)
    }
  }
})

5.2 防抖点击指令

javascript 复制代码
app.directive('debounce-click', {
  mounted(el, binding) {
    const delay = binding.value || 500
    let timer = null
    
    el.addEventListener('click', () => {
      if (timer) clearTimeout(timer)
      timer = setTimeout(() => {
        binding.arg && binding.arg()
      }, delay)
    })
  },
  unmounted(el) {
    el.removeEventListener('click')
  }
})

5.3 拖拽指令

javascript 复制代码
app.directive('drag', {
  mounted(el) {
    let isDragging = false
    let offsetX, offsetY
    
    el.style.position = 'absolute'
    el.style.cursor = 'move'
    
    el.addEventListener('mousedown', (e) => {
      isDragging = true
      offsetX = e.clientX - el.getBoundingClientRect().left
      offsetY = e.clientY - el.getBoundingClientRect().top
    })
    
    document.addEventListener('mousemove', (e) => {
      if (!isDragging) return
      el.style.left = e.clientX - offsetX + 'px'
      el.style.top = e.clientY - offsetY + 'px'
    })
    
    document.addEventListener('mouseup', () => {
      isDragging = false
    })
  }
})

5.4 图片懒加载指令

javascript 复制代码
app.directive('lazy', {
  mounted(el, binding) {
    const observer = new IntersectionObserver((entries) => {
      entries.forEach(entry => {
        if (entry.isIntersecting) {
          el.src = binding.value
          observer.unobserve(el)
        }
      })
    })
    observer.observe(el)
  }
})

6.注意事项

在 setup() 中定义的指令必须以 v 开头(如 vFocus),才能在模板中作为 v-focus 使用
指令必须从 setup() 中返回才能在模板中使用
对于需要清理的资源(如事件监听器),确保在 unmounted 钩子中进行清理
指令的 binding 参数是响应式的,但 el 不是
在 <script setup> 中定义的指令会自动暴露给模板,无需显式返回

相关推荐
子兮曰2 天前
jev-ultrafast 深度解析:7 秒订机票的浏览器 Agent 是如何炼成的
前端·后端·agent
子兮曰2 天前
Jev 爆发一周:7 秒 Agent 背后的 System One 生态与三场争议
前端·后端·ai编程
前端小万2 天前
写公众号赚了 3000 块后,我做了一款叫 "一键成稿" 的软件
前端·微信小程序
爱勇宝2 天前
ZCode 开源 24 小时:一份没有历史的账本,回答不了"有没有偷代码"
前端·后端·chatglm (智谱)
A黄俊辉A2 天前
uniapp webview中实现 app和内嵌的H5双向通信
vue.js·json
三十而立洋2 天前
Cookie 详解:从产生到安全,一次讲透
前端·javascript
卡布鲁2 天前
把一个 Vite + Vue3 应用塞进 qiankun (React + Umi3) 主站:十个坑的复盘
前端·javascript·react.js
李少兄2 天前
JavaScript 隐式全局变量解析
javascript
honkun62 天前
vue 表格组件 vxe-table 配置 ajax 请求自动加载数据与表单查询
vue.js·vxe-table
kybs19912 天前
全球灾害数据分析可视化 毕业设计-附源码66794
vue.js·spring boot·mysql·安全·django·c#·asp.net