当前位置: 首页 > news >正文

Vue3 学习教程,从入门到精通, Vue3 自定义指令语法知识点及案例(20)

Vue3 自定义指令语法知识点及案例

在 Vue3 中,自定义指令允许你封装可重用的行为,以增强 DOM 元素的功能。自定义指令分为全局指令局部指令,并且提供了丰富的钩子函数来控制指令的生命周期和行为。以下将详细介绍 Vue3 自定义指令的语法知识点,并通过详细的案例代码进行说明。


目录

  1. 自定义指令的基本概念
  2. 全局自定义指令
  3. 局部自定义指令
  4. 自定义指令的钩子函数
  5. 钩子函数的参数
  6. 案例:实现一个简单的拖拽指令
  7. 案例:实现一个防抖输入指令
  8. 总结

1. 自定义指令的基本概念

自定义指令允许开发者将可重用的行为封装起来,以便在模板中重复使用。它们主要用于需要在 DOM 元素上添加低级别的 DOM 操作时。

指令的命名

  • kebab-case:使用短横线分隔,如 v-my-directive
  • camelCase:在模板中使用时需要转换为 kebab-case,如 vMyDirective 在模板中应写为 v-my-directive

使用方式

<!-- 全局指令 -->
<div v-focus></div><!-- 局部指令 -->
<div v-local-directive></div>

2. 全局自定义指令

全局自定义指令可以在任何组件中使用。通过 app.directive 方法进行注册。

语法

// 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')

使用示例

<!-- App.vue -->
<template><input v-focus placeholder="自动获取焦点" />
</template>

3. 局部自定义指令

局部自定义指令只能在定义它的组件中使用。通过在组件的 directives 选项中注册。

语法

// MyComponent.vue
<template><input v-local-focus placeholder="局部自动获取焦点" />
</template><script>
export default {directives: {localFocus: {mounted(el) {el.focus()}}}
}
</script>

使用示例

<!-- MyComponent.vue -->
<template><input v-local-focus placeholder="局部自动获取焦点" />
</template><script>
export default {directives: {localFocus: {mounted(el) {el.focus()}}}
}
</script>

4. 自定义指令的钩子函数

Vue3 提供了多个钩子函数来控制指令的行为:

  • beforeMount:在绑定元素的 attribute 或事件监听器被应用之前调用。
  • mounted:在绑定元素的父组件被挂载后调用。
  • beforeUpdate:在包含该指令的组件的 VNode 更新之前调用。
  • updated:在包含该指令的组件的 VNode 及其子组件的 VNode 全部更新后调用。
  • beforeUnmount:在绑定元素的父组件卸载之前调用。
  • unmounted:在绑定元素的父组件卸载后调用。

钩子函数示例

app.directive('example', {beforeMount(el, binding, vnode) {// 在元素挂载之前执行},mounted(el, binding, vnode) {// 在元素挂载后执行},beforeUpdate(el, binding, vnode, prevVnode) {// 在元素更新之前执行},updated(el, binding, vnode, prevVnode) {// 在元素更新后执行},beforeUnmount(el, binding, vnode) {// 在元素卸载之前执行},unmounted(el, binding, vnode) {// 在元素卸载后执行}
})

5. 钩子函数的参数

每个钩子函数都接收以下参数:

  • el:指令绑定的元素。
  • binding:一个对象,包含以下属性:
    • instance:使用指令的组件实例。
    • value:传递给指令的值。
    • oldValue:前一个值,仅在 beforeUpdateupdated 中可用。
    • arg:传递给指令的参数(如 v-my-directive:foo 中的 foo)。
    • modifiers:一个包含修饰符的对象(如 v-my-directive.foo.bar 中的 { foo: true, bar: true })。
  • vnode:Vue 编译生成的虚拟节点。
  • prevVnode:前一个虚拟节点,仅在 beforeUpdateupdated 中可用。

参数示例

app.directive('log', {mounted(el, binding, vnode) {console.log('Directive mounted')console.log('Element:', el)console.log('Binding value:', binding.value)console.log('Argument:', binding.arg)console.log('Modifiers:', binding.modifiers)}
})

6. 案例:实现一个简单的拖拽指令

功能描述

实现一个 v-drag 指令,使元素可以通过拖拽移动。

实现步骤

  1. 注册全局指令 v-drag
  2. mounted 钩子中绑定鼠标事件
  3. unmounted 钩子中移除事件监听
  4. 实现拖拽逻辑

代码实现

<!-- App.vue -->
<template><div id="app"><div v-drag class="draggable-box">拖拽我!</div></div>
</template><script>
export default {name: 'App'
}
</script><style>
.draggable-box {width: 100px;height: 100px;background-color: #42b983;color: white;display: flex;align-items: center;justify-content: center;cursor: move;position: absolute;top: 100px;left: 100px;
}
</style>
// main.js
import { createApp } from 'vue'
import App from './App.vue'const app = createApp(App)// 定义全局拖拽指令
app.directive('drag', {mounted(el) {let isDragging = falselet offsetX = 0let offsetY = 0const down = (e) => {isDragging = true// 获取鼠标相对于元素的位置offsetX = e.clientX - el.getBoundingClientRect().leftoffsetY = e.clientY - el.getBoundingClientRect().topel.style.transition = 'none'}const move = (e) => {if (isDragging) {el.style.left = `${e.clientX - offsetX}px`el.style.top = `${e.clientY - offsetY}px`}}const up = () => {isDragging = falseel.style.transition = 'all 0.2s'}el.addEventListener('mousedown', down)document.addEventListener('mousemove', move)document.addEventListener('mouseup', up)// 清理事件监听器el._dragCleanup = () => {el.removeEventListener('mousedown', down)document.removeEventListener('mousemove', move)document.removeEventListener('mouseup', up)}},unmounted(el) {if (el._dragCleanup) {el._dragCleanup()}}
})app.mount('#app')

代码说明

  1. HTML 部分

    • 使用 v-drag 指令绑定到 div 元素上,使其可拖拽。
    • 设置 position: absolute 以便通过 lefttop 属性移动元素。
  2. CSS 部分

    • 设置拖拽元素的样式,包括大小、颜色、位置等。
  3. JavaScript 部分

    • mounted 钩子
      • 定义 isDragging 标志位,标识是否正在拖拽。
      • 计算鼠标相对于元素的位置,以便正确计算移动后的位置。
      • 绑定 mousedownmousemovemouseup 事件。
      • mousedown 时记录当前鼠标位置,并开始拖拽。
      • mousemove 时根据鼠标移动的位置更新元素的位置。
      • mouseup 时结束拖拽。
    • unmounted 钩子
      • 移除所有事件监听器,防止内存泄漏。

7. 案例:实现一个防抖输入指令

功能描述

实现一个 v-debounce 指令,使输入框在用户停止输入一段时间后触发事件(如搜索)。

实现步骤

  1. 注册全局指令 v-debounce
  2. mounted 钩子中绑定 input 事件
  3. 实现防抖逻辑
  4. unmounted 钩子中移除事件监听

代码实现

<!-- App.vue -->
<template><div id="app"><input v-debounce="500" @debounce="onDebounce" placeholder="输入内容后停止500ms触发" /></div>
</template><script>
export default {name: 'App',methods: {onDebounce(value) {console.log('防抖输入内容:', value)}}
}
</script><style>
input {padding: 10px;font-size: 16px;
}
</style>
// main.js
import { createApp } from 'vue'
import App from './App.vue'const app = createApp(App)// 定义全局防抖输入指令
app.directive('debounce', {mounted(el, binding) {let timeout = nullconst delay = binding.value || 300const handler = () => {const event = new Event('debounce')el.dispatchEvent(event)}el.addEventListener('input', () => {if (timeout) clearTimeout(timeout)timeout = setTimeout(handler, delay)})},unmounted(el) {if (el._debounceCleanup) {el._debounceCleanup()}}
})app.mount('#app')

代码说明

  1. HTML 部分

    • 使用 v-debounce 指令绑定到 input 元素上,传递延迟时间(500ms)。
    • 监听 debounce 自定义事件,在防抖触发时调用 onDebounce 方法。
  2. JavaScript 部分

    • mounted 钩子
      • 定义防抖延迟时间 delay,默认为 300ms。
      • 定义 handler 函数,用于触发 debounce 事件。
      • 绑定 input 事件,在用户输入时启动一个定时器。
      • 如果在延迟时间内再次输入,清除之前的定时器,重新启动。
    • unmounted 钩子
      • 移除所有事件监听器,防止内存泄漏。
  3. 事件触发

    • 当用户停止输入超过 500ms 后,debounce 事件被触发,onDebounce 方法被调用。

事件处理

// App.vue
<script>
export default {name: 'App',methods: {onDebounce(value) {console.log('防抖输入内容:', value)// 这里可以添加其他逻辑,如发起搜索请求}}
}
</script>

8. 总结

通过以上内容,我们了解了 Vue3 中自定义指令的基本概念、全局与局部指令的区别、钩子函数的种类及其参数。同时,通过两个具体的案例,我们展示了如何实现一个简单的拖拽指令和一个防抖输入指令。这些知识将帮助你在 Vue3 项目中更有效地使用自定义指令,提升代码的可重用性和可维护性。

注意事项

  • 命名规范:使用 kebab-case 命名指令,避免与内置指令冲突。
  • 性能考虑:避免在指令中进行复杂的计算或操作,以免影响性能。
  • 清理工作:在 unmounted 钩子中清理事件监听器,防止内存泄漏。
  • 作用域:全局指令适用于多个组件,局部指令适用于单个组件。
http://www.dtcms.com/a/304612.html

相关文章:

  • c++ nlohmann/json读写json文件
  • JavaWeb学习打卡18(JDBC案例详解)
  • ansible 使用更高版本的python版本
  • Python中的决策树机器学习模型简要介绍和代码示例(基于sklearn)
  • 【牛客网C语言刷题合集】(五)——主要二进制、操作符部分
  • GO 开发环境安装及配置
  • Claude Code 使用教程(对接智谱模型)
  • 84、【OS】【Nuttx】【启动】栈溢出保护:asm 关键字(下)
  • SpringBoot集成Quzrtz实现定时任务
  • 【目标检测】小样本度量学习
  • 记录一个TI DSP编译器的Bug
  • CentOS安装ffmpeg并转码视频为mp4
  • 预过滤环境光贴图制作教程:第四阶段 - Lambert 无权重预过滤(Stage 3)
  • 预过滤环境光贴图制作教程:第一步 - HDR 转立方体贴图
  • Android Compose 自定义组件完全指南
  • 对College数据进行多模型预测(R语言)
  • 《React与Vue构建TODO应用的深层逻辑》
  • 【lucene】SegmentCoreReaders
  • linux_前台,后台进程
  • LeetCode热题100——155. 最小栈
  • (LeetCode 面试经典 150 题) 150. 逆波兰表达式求值 (栈)
  • 电脑主机显示的python版本是3.8.6,但是我在控制面板没有找到,想删除不知道怎么操作怎么办
  • 《 java 随想录》| LeetCode链表高频考题
  • 【LeetCode】大厂面试算法真题回忆(111)--身高排序
  • 鱼皮项目简易版 RPC 框架开发(五)
  • 2.oracle保姆级安装教程
  • 逐渐走进Ai世界~
  • Django模型开发:模型字段、元数据与继承全方位讲解
  • Unity_SRP Batcher
  • 【WRF-Chem 实例1】namelist.input 详解- 模拟CO2