Vue自定义指令:从入门到实战应用

一、自定义指令基础概念

官方文档:自定义指令

1.1 什么是自定义指令?

Vue自定义指令是对原生DOM操作的高级封装,用于扩展HTML元素的功能。它允许开发者创建可复用的DOM行为,主要应用于以下场景:

  • DOM底层操作(如聚焦、拖拽)
  • 集成第三方DOM库
  • 创建可视化特效

1.2 生命周期钩子

钩子函数 触发时机 典型应用场景
created 元素属性初始化时 访问初始化属性值
beforeMount 元素插入DOM前 预加载资源
mounted 元素插入DOM后 DOM操作(最常用)
beforeUpdate 绑定值更新前 保存旧状态
updated 绑定值更新后 响应数据变化
beforeUnmount 元素卸载前 清理定时器
unmounted 元素卸载后 移除事件监听

二、指令注册方式详解

2.1 全局注册

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

const app = createApp(App)

// 方式1:直接注册
app.directive('focus', { //focus指令
  mounted(el) {  //mounted时生效
    el.focus()
  }
})

// 方式2:模块化注册  //代码更加优雅
import draggable from './directives/draggable'
app.directive('draggable', draggable)

2.2 局部注册(组件级)

vue 复制代码
<script setup>
// 方式1:函数式指令
const vColor = (el, binding) => {
  el.style.color = binding.value
}

// 方式2:对象式指令
const vHighlight = {
  mounted(el, binding) {
    el.style.backgroundColor = binding.value
  },
  updated(el, binding) {
    el.style.backgroundColor = binding.value
  }
}
</script>

三、实战案例解析

3.1 案例一:元素拖拽指令

3.1.1. 定义指令

js 复制代码
// 定义自定义指令
export default {
  mounted(el) {
    // 鼠标放上去时,改变鼠标样式为"move"
    el.style.cursor = 'move'
    el.style.position = 'relative'

    // 监听鼠标按下事件
    el.onmousedown = function(e) {
      // 获取鼠标按下时相对元素的偏移
      let disX = e.pageX - el.offsetLeft
      let disY = e.pageY - el.offsetTop

      // 监听鼠标移动事件
      document.onmousemove = function(e) {
        let x = e.pageX - disX
        let y = e.pageY - disY

        // 边界检测
        let maxX = document.body.clientWidth - el.offsetWidth
        let maxY = document.body.clientHeight - el.offsetHeight

        // 限制元素在页面中的最大和最小位置
        if (x < 0) x = 0
        if (x > maxX) x = maxX
        if (y < 0) y = 0
        if (y > maxY) y = maxY

        // 设置元素的新位置
        el.style.left = `${x}px`
        el.style.top = `${y}px`
      }

      // 监听鼠标释放事件
      document.onmouseup = function() {
        // 取消事件
        document.onmousemove = null
        document.onmouseup = null
      }
    }
  }
}

3.1.2. 注册指令

指令的定义需要一个install函数,该函数用于注册指令到Vue实例中。Vue会调用install函数来将指令注册到全局或局部。

js 复制代码
//  ./command/index.js'
import Draggable from './draggable.js'
// 统一注册
const directive = {
  Draggable
  //...
  //...
}

export default {
  install(app) {
    // 注册自定义指令
    Object.keys(directive).forEach(key => {
      app.directive(key, directive[key])  //指令需要通过`app.directive`来注册。
    })
  }
}

然后在main.js中挂载。

js 复制代码
import { createApp } from 'vue'
import './style.css'
import App from './App.vue'
import Directives from './command/index.js'

const app = createApp(App)
app.use(Directives) // 全局注册 // 注册指令use调用了install 函数,触发注册
app.mount('#app')

3.1.3. 在组件中使用指令

自定义指令注册后,你就可以在模板中使用它了。假设你创建了一个v-draggable指令来使元素可拖拽,下面是如何使用它的示例:

vue 复制代码
<template>
  <div class="box" v-draggable></div>
</template>

<script setup>
// 这里不需要特别的代码,因为指令已经在全局注册过
</script>

<style lang="css" scoped>
.box {
  width: 100px;
  height: 100px;
  background-color: #f00;
}
</style>

3.2 案例二:动态颜色指令

javascript 复制代码
// 对象式写法(推荐)
export default {
// el:该指令绑定在哪个元素上   binding:指令的相关信息,包含该指令绑定的值
  mounted(el, binding) {  
    updateColor(el, binding.value);
  },
  updated(el, binding) {
    updateColor(el, binding.value);
  }
}

// 函数式写法(同时触发mounted和updated)
// export default (el, binding) => {
//   updateColor(el, binding.value)
// }

function updateColor(el, value) {
  const length = value?.length || 0;
  
  if (length <= 5) {
    el.style.color = 'green';
  } else if (length <= 10) {
    el.style.color = 'goldenrod';
  } else {
    el.style.color = 'red';
  }
}

3.1.3. 使用示例

vue 复制代码
<template>
  <div class="input-group">
    <input 
      type="text" 
      v-model="inputVal"
      placeholder="输入内容观察颜色变化"
    >
    <h3 v-highlight="inputVal">{{ inputVal }}</h3>
  </div>
</template>

<script setup>
import { ref } from 'vue';
const inputVal = ref('');
</script>

<style>
.input-group {
  margin: 20px;
  padding: 15px;
  border: 1px solid #eee;
}

h3 {
  transition: color 0.3s;
  padding: 10px;
  border-radius: 4px;
}
</style>
相关推荐
juruiyuan11123 分钟前
FFmpeg3.4 libavcodec协议框架增加新的decode协议
前端
Peter 谭1 小时前
React Hooks 实现原理深度解析:从基础到源码级理解
前端·javascript·react.js·前端框架·ecmascript
周胡杰1 小时前
鸿蒙接入flutter环境变量配置windows-命令行或者手动配置-到项目的创建-运行demo项目
javascript·windows·flutter·华为·harmonyos·鸿蒙·鸿蒙系统
LuckyLay2 小时前
React百日学习计划——Deepseek版
前端·学习·react.js
gxn_mmf2 小时前
典籍知识问答重新生成和消息修改Bug修改
前端·bug
hj10432 小时前
【fastadmin开发实战】在前端页面中使用bootstraptable以及表格中实现文件上传
前端
乌夷2 小时前
axios结合AbortController取消文件上传
开发语言·前端·javascript
晓晓莺歌3 小时前
图片的require问题
前端
码农黛兮_463 小时前
CSS3 基础知识、原理及与CSS的区别
前端·css·css3
水银嘻嘻4 小时前
web 自动化之 Unittest 四大组件
运维·前端·自动化