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>
相关推荐
万少7 小时前
HarmonyOS 开发必会 5 种 Builder 详解
前端·harmonyos
橙序员小站9 小时前
Agent Skill 是什么?一文讲透 Agent Skill 的设计与实现
前端·后端
炫饭第一名11 小时前
速通Canvas指北🦮——基础入门篇
前端·javascript·程序员
王晓枫12 小时前
flutter接入三方库运行报错:Error running pod install
前端·flutter
符方昊12 小时前
React 19 对比 React 16 新特性解析
前端·react.js
ssshooter12 小时前
又被 Safari 差异坑了:textContent 拿到的值居然没换行?
前端
曲折12 小时前
Cesium-气象要素PNG色斑图叠加
前端·cesium
Forever7_12 小时前
Electron 淘汰!新的桌面端框架 更强大、更轻量化
前端·vue.js
不会敲代码112 小时前
前端组件化样式隔离实战:React CSS Modules、styled-components 与 Vue scoped 对比
css·vue.js·react.js
Angelial12 小时前
Vue3 嵌套路由 KeepAlive:动态缓存与反向配置方案
前端·vue.js