本文主要是介绍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. 元素拖拽
<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的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!