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>
相关推荐
zwjapple5 小时前
docker-compose一键部署全栈项目。springboot后端,react前端
前端·spring boot·docker
像风一样自由20207 小时前
HTML与JavaScript:构建动态交互式Web页面的基石
前端·javascript·html
aiprtem8 小时前
基于Flutter的web登录设计
前端·flutter
浪裡遊8 小时前
React Hooks全面解析:从基础到高级的实用指南
开发语言·前端·javascript·react.js·node.js·ecmascript·php
why技术8 小时前
Stack Overflow,轰然倒下!
前端·人工智能·后端
幽络源小助理8 小时前
SpringBoot基于Mysql的商业辅助决策系统设计与实现
java·vue.js·spring boot·后端·mysql·spring
GISer_Jing8 小时前
0704-0706上海,又聚上了
前端·新浪微博
止观止8 小时前
深入探索 pnpm:高效磁盘利用与灵活的包管理解决方案
前端·pnpm·前端工程化·包管理器
whale fall8 小时前
npm install安装的node_modules是什么
前端·npm·node.js
烛阴8 小时前
简单入门Python装饰器
前端·python