vue3从精通到入门21:自定义指令directive

本文主要是介绍vue3从精通到入门21:自定义指令directive,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

Vue3中的自定义指令directive是一种扩展HTML标签能力的机制。通过自定义指令,开发者可以直接在模板中使用指令名,并为其提供相应的逻辑。这些指令在Vue应用程序中扮演着重要角色,允许开发者执行一些低级DOM操作或访问元素状态。

自定义指令的钩子函数

自定义指令可以包含多个钩子函数,它们在指令的不同生命周期阶段被调用:

  • beforeMount(el, binding, vnode, prevVnode): 在元素被插入到 DOM 之前调用。
  • mounted(el, binding, vnode, prevVnode): 在元素被插入到 DOM 后调用。
  • beforeUpdate(el, binding, vnode, prevVnode): 在元素更新之前调用。
  • updated(el, binding, vnode, prevVnode): 在元素更新后调用。
  • beforeUnmount(el, binding, vnode, prevVnode): 在元素被移除之前调用。
  • unmounted(el, binding, vnode, prevVnode): 在元素被移除后调用。

这些钩子函数都接收相同的参数:

  • el: 指令所绑定的元素,可以用来直接操作 DOM。
  • binding: 一个对象,包含以下属性:
    • name: 指令名,不包括 v- 前缀。
    • value: 指令的绑定值,例如:v-my-directive="1 + 1" 中,绑定值为 2
    • oldValue: 指令绑定的前一个值,仅在 update 和 componentUpdated 钩子中可用。无论值是否改变都可用。
    • expression: 字符串形式的指令表达式。例如 v-my-directive="1 + 1" 中,表达式为 "1 + 1"
    • arg: 传给指令的参数,可选。例如 v-my-directive:foo 中,参数为 "foo"
    • modifiers: 一个包含修饰符的对象。例如:v-my-directive.foo.bar 中,修饰符对象为 { foo: true, bar: true }
  • vnode: Vue 虚拟节点。
  • prevVnode: 上一个虚拟节点,仅在 update 和 componentUpdated 钩子中可用。

使用方法

1. 定义自定义指令 

直接定义自定义指令,并通过 defineDirective 函数将其注册为局部指令。

<template>  <input v-focus />  
</template>  <script setup lang="ts">  
import { defineDirective } from 'vue'  // 定义一个名为 'focus' 的自定义指令  
const focusDirective = defineDirective({  // 当元素被插入到 DOM 中时调用  mounted(el: HTMLElement) {  el.focus()  },  // 当元素更新时调用  updated(el: HTMLElement) {  // 这里可以添加更新时的逻辑,比如重新聚焦等  }  
})  // 注册局部自定义指令  
defineDirective('focus', focusDirective)  
</script>

在上面的代码中,我们首先通过 import { defineDirective } from 'vue' 导入了 defineDirective 函数。然后,我们定义了一个名为 focusDirective 的对象,它包含了自定义指令的钩子函数。最后,我们使用 defineDirective 函数将 focusDirective 注册为名为 focus 的局部自定义指令。

2. 使用自定义指令

<template>  <input v-focus placeholder="这个输入框会自动聚焦" />  
</template>

3. 带参数的自定义指令

<template>  <div v-scroll-to="'top'">滚动到顶部</div>  <div v-scroll-to="'bottom'">滚动到底部</div>  
</template>  <script setup lang="ts">  
import { defineDirective, onMounted, onUpdated, ref } from 'vue'  const scrollToDirective = defineDirective({  mounted(el, binding) {  const scrollTarget

使用场景

我们在实际项目中,会遇到各种场景,以下是典型场景:

  1. 焦点管理:自动设置输入框的焦点。
  2. 元素拖拽:使元素可以拖拽。
  3. 图片懒加载:延迟加载图片直到它们进入视口。
  4. 文本高亮:根据条件高亮文本中的特定部分。
  5. 权限控制:基于用户权限控制元素的显示或隐藏。

焦点管理已经在上述例子中讲解过;

1. 元素拖拽

<template>  <div id="app">  <div v-drag>Drag me</div>  </div>  
</template>  <script setup lang="ts">  
import { ref, onMounted, onUnmounted } from 'vue';  // 自定义指令 v-drag  
const dragDirective = {  mounted(el: HTMLElement) {  let offsetX = 0;  let offsetY = 0;  let isDragging = false;  const handleMousedown = (event: MouseEvent) => {  offsetX = event.clientX - el.offsetLeft;  offsetY = event.clientY - el.offsetTop;  isDragging = true;  document.addEventListener('mousemove', handleMousemove);  document.addEventListener('mouseup', handleMouseup);  };  const handleMousemove = (event: MouseEvent) => {  if (!isDragging) return;  const x = event.clientX - offsetX;  const y = event.clientY - offsetY;  el.style.transform = `translate(${x}px, ${y}px)`;  };  const handleMouseup = () => {  isDragging = false;  document.removeEventListener('mousemove', handleMousemove);  document.removeEventListener('mouseup', handleMouseup);  };  el.addEventListener('mousedown', handleMousedown);  },  unmounted() {  // 清理事件监听器  document.removeEventListener('mousemove', handleMousemove);  document.removeEventListener('mouseup', handleMouseup);  }  
};  // 注册自定义指令  
const drag = directive(dragDirective);  
</script>  <style scoped>  
#app {  width: 100%;  height: 100vh;  display: flex;  justify-content: center;  align-items: center;  
}  
div {  width: 100px;  height: 100px;  background-color: skyblue;  cursor: move;  user-select: none; /* 禁止文本选择 */  
}  
</style>

2. 图片懒加载

<template>  <div id="app">  <img v-lazy="imageSrc" alt="Lazy loaded image">  </div>  
</template>  <script setup lang="ts">  
import { ref, onMounted, onUnmounted } from 'vue';  // 自定义指令 v-lazy  
const lazyDirective = {  mounted(el: HTMLImageElement, binding: any) {  const observer = new IntersectionObserver((entries, observer) => {  entries.forEach(entry => {  if (entry.isIntersecting) {  // 当图片进入视口时,设置图片的src属性  el.src = binding.value;  // 停止观察  observer.unobserve(el);  }  });  },  { threshold: 0.1 } // 提前加载,可以设置阈值  );  observer.observe(el);  
},  
unmounted() {  // 组件卸载时,停止观察  observer.unobserve(el);  
}  
};  // 注册自定义指令  
const lazy = directive(lazyDirective);  const imageSrc = ref('path/to/your/image.jpg'); // 图片地址  
</script>  <style scoped>  
#app {  width: 100%;  height: 100vh;  display: flex;  justify-content: center;  align-items: center;  
}  
img {  width: 300px;  height: 200px;  
}  
</style>

3. 文本高亮

<template>  <div id="app">  <p v-highlight="'Vue 3'">Vue 3 is awesome!</p>  </div>  
</template>  <script setup lang="ts">  
import { Directive } from 'vue';  // 自定义指令 v-highlight  
const highlightDirective: Directive = {  // 当绑定元素插入到 DOM 中。  mounted(el, binding) {  // 获取绑定值,即要高亮显示的文本  const searchTerm = binding.value.toString();  // 创建一个正则表达式,用于全局不区分大小写的匹配  const regex = new RegExp(searchTerm, 'gi');  // 获取元素的文本内容  const textContent = el.textContent || '';  // 使用replace方法替换匹配到的文本,并添加高亮样式  const highlightedText = textContent.replace(regex, (matchedText) => {  return `<mark>${matchedText}</mark>`;  });  // 设置元素的innerHTML为高亮后的文本  el.innerHTML = highlightedText;  },  // 当绑定元素更新时  updated(el, binding) {  // 更新文本高亮  this.mounted(el, binding);  }  
};  // 注册自定义指令  
const highlight = directive(highlightDirective);  
</script>  <style scoped>  
#app {  width: 100%;  height: 100vh;  display: flex;  justify-content: center;  align-items: center;  
}  
mark {  background-color: yellow;  
}  
</style>

4. 权限控制

<template>  <div id="app">  <!-- 使用v-permission指令,参数为所需的权限 -->  <button v-permission="'admin'">Admin Only Button</button>  <button v-permission="'user'">User Button</button>  </div>  
</template>  <script setup lang="ts">  
import { ref, onMounted, Directive } from 'vue';  // 假设这是从后端或其他地方获取的当前用户的权限  
const userPermissions = ref(['user']);  // 自定义指令 v-permission  
const permissionDirective: Directive = {  mounted(el, binding) {  // 获取指令的绑定值,即所需的权限  const requiredPermission = binding.value;  // 检查用户是否有权限  if (!userPermissions.value.includes(requiredPermission)) {  // 如果没有权限,隐藏元素  el.style.display = 'none';  }  },  updated(el, binding) {  // 当指令的值更新时,重新检查权限  this.mounted(el, binding);  }  
};  // 注册自定义指令  
const permission = directive(permissionDirective);  // 示例:模拟从后端获取用户权限  
onMounted(() => {  // 假设这是从后端API或其他地方获取权限的模拟  // 在实际应用中,你会在用户登录或其他时机获取这些权限  setTimeout(() => {  // 假设当前用户只有'user'权限  userPermissions.value = ['user'];  }, 1000);  
});  
</script>  <style scoped>  
#app {  width: 100%;  height: 100vh;  display: flex;  flex-direction: column;  align-items: center;  justify-content: center;  
}  
</style>

这篇关于vue3从精通到入门21:自定义指令directive的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/894816

相关文章

Vue3 的 shallowRef 和 shallowReactive:优化性能

大家对 Vue3 的 ref 和 reactive 都很熟悉,那么对 shallowRef 和 shallowReactive 是否了解呢? 在编程和数据结构中,“shallow”(浅层)通常指对数据结构的最外层进行操作,而不递归地处理其内部或嵌套的数据。这种处理方式关注的是数据结构的第一层属性或元素,而忽略更深层次的嵌套内容。 1. 浅层与深层的对比 1.1 浅层(Shallow) 定义

Spring Security 从入门到进阶系列教程

Spring Security 入门系列 《保护 Web 应用的安全》 《Spring-Security-入门(一):登录与退出》 《Spring-Security-入门(二):基于数据库验证》 《Spring-Security-入门(三):密码加密》 《Spring-Security-入门(四):自定义-Filter》 《Spring-Security-入门(五):在 Sprin

这15个Vue指令,让你的项目开发爽到爆

1. V-Hotkey 仓库地址: github.com/Dafrok/v-ho… Demo: 戳这里 https://dafrok.github.io/v-hotkey 安装: npm install --save v-hotkey 这个指令可以给组件绑定一个或多个快捷键。你想要通过按下 Escape 键后隐藏某个组件,按住 Control 和回车键再显示它吗?小菜一碟: <template

【 html+css 绚丽Loading 】000046 三才归元阵

前言:哈喽,大家好,今天给大家分享html+css 绚丽Loading!并提供具体代码帮助大家深入理解,彻底掌握!创作不易,如果能帮助到大家或者给大家一些灵感和启发,欢迎收藏+关注哦 💕 目录 📚一、效果📚二、信息💡1.简介:💡2.外观描述:💡3.使用方式:💡4.战斗方式:💡5.提升:💡6.传说: 📚三、源代码,上代码,可以直接复制使用🎥效果🗂️目录✍️

【前端学习】AntV G6-08 深入图形与图形分组、自定义节点、节点动画(下)

【课程链接】 AntV G6:深入图形与图形分组、自定义节点、节点动画(下)_哔哩哔哩_bilibili 本章十吾老师讲解了一个复杂的自定义节点中,应该怎样去计算和绘制图形,如何给一个图形制作不间断的动画,以及在鼠标事件之后产生动画。(有点难,需要好好理解) <!DOCTYPE html><html><head><meta charset="UTF-8"><title>06

数论入门整理(updating)

一、gcd lcm 基础中的基础,一般用来处理计算第一步什么的,分数化简之类。 LL gcd(LL a, LL b) { return b ? gcd(b, a % b) : a; } <pre name="code" class="cpp">LL lcm(LL a, LL b){LL c = gcd(a, b);return a / c * b;} 例题:

Java 创建图形用户界面(GUI)入门指南(Swing库 JFrame 类)概述

概述 基本概念 Java Swing 的架构 Java Swing 是一个为 Java 设计的 GUI 工具包,是 JAVA 基础类的一部分,基于 Java AWT 构建,提供了一系列轻量级、可定制的图形用户界面(GUI)组件。 与 AWT 相比,Swing 提供了许多比 AWT 更好的屏幕显示元素,更加灵活和可定制,具有更好的跨平台性能。 组件和容器 Java Swing 提供了许多

【IPV6从入门到起飞】5-1 IPV6+Home Assistant(搭建基本环境)

【IPV6从入门到起飞】5-1 IPV6+Home Assistant #搭建基本环境 1 背景2 docker下载 hass3 创建容器4 浏览器访问 hass5 手机APP远程访问hass6 更多玩法 1 背景 既然电脑可以IPV6入站,手机流量可以访问IPV6网络的服务,为什么不在电脑搭建Home Assistant(hass),来控制你的设备呢?@智能家居 @万物互联

poj 2104 and hdu 2665 划分树模板入门题

题意: 给一个数组n(1e5)个数,给一个范围(fr, to, k),求这个范围中第k大的数。 解析: 划分树入门。 bing神的模板。 坑爹的地方是把-l 看成了-1........ 一直re。 代码: poj 2104: #include <iostream>#include <cstdio>#include <cstdlib>#include <al

计算机毕业设计 大学志愿填报系统 Java+SpringBoot+Vue 前后端分离 文档报告 代码讲解 安装调试

🍊作者:计算机编程-吉哥 🍊简介:专业从事JavaWeb程序开发,微信小程序开发,定制化项目、 源码、代码讲解、文档撰写、ppt制作。做自己喜欢的事,生活就是快乐的。 🍊心愿:点赞 👍 收藏 ⭐评论 📝 🍅 文末获取源码联系 👇🏻 精彩专栏推荐订阅 👇🏻 不然下次找不到哟~Java毕业设计项目~热门选题推荐《1000套》 目录 1.技术选型 2.开发工具 3.功能