自定义指令
什么是自定义指令
在 Vue 的模板语法中我们学习过各种各样的指令:v-show、v-for、v-model 等等,除了使用这些指令之外,Vue 也允许我们来自定义自己的指令。
通常在某些情况下,你需要对 DOM 元素进行底层操作,这个时候就会用到自定义指令。
自定义指令分为 局部自定义指令 跟 全局自定义指令。
局部自定义指令
局部自定义指令就是只能在当前组件内使用的自定义指令,通过 directives 选项来定义:
export default {
directives: {
focus: {
mounted(el, bindings, vnode, preVnode) {
console.log(el, bindings, vnode, preVnode)
el.focus()
}
}
},
setup() {}
}
<!-- 指令的使用 -->
<input type="text" v-focus />
注:不可以在 setup 函数中定义指令。
全局自定义指令
全局自定义指令可以在任意组件内使用,通过 vue 实例的 directive 方式来定义:
在 main.js 文件中:
const app = createApp(App);
app.directive("focus", {
mounted(el, bindings, vnode, preVnode) {
console.log(el, bindings, vnode, preVnode);
el.focus();
},
});
自定义指令的生命周期
对于使用了指令的元素,Vue 提供了以下的钩子函数:
- created:在元素的属性及事件监听应用之前调用;
- beforeMount:指令绑定到元素后,且父组件挂载之前调用;
- mounted:绑定元素的父组件挂载后调用;
- beforeUpdate:
- updated:
- beforeUnmount:绑定元素的父组件卸载前调用;
- unmounted:绑定元素的父组件卸载时调用##
自定义指令的参数跟修饰符
在使用自定义指令时可以添加修饰符及接收参数:
<input type="text" v-focus.abc.def="'caohan'" />
abc 跟 def 都是修饰符,也就是说修饰符可以不止一个。'caohan' 就是接收的参数的值。在自定义指令的生命周期钩子函数中,可以获取到在该元素上使用的修饰符及传过来的参数:
directives: {
focus: {
created(el, bindings) {
console.log(bindings.modifiers) // { abc: true, def: true }
console.log(bindings.value) // caohan
},
}
},
修饰符是以对象的形式返回,且值始终为 true。参数的值可以是字符串数值布尔值,也可以是对象或数组。
自定义指令的时间戳格式化案例
将返回的时间戳数据转换成具体格式化的时间来展示,除了可以使用计算属性 computed 跟 methods 外,还可以通过自定义指令来完成。
代码实现
<template>
<div>
<h2 v-format-time="'YYYY/MM/DD'">1666452738</h2>
</div>
</template>
// 使用第三方的库来实现格式化功能
import dayjs from 'dayjs'
export default {
directives: {
'format-time': {
created(el, bindings) {
// 将初始化数据的逻辑抽取到 created 里面
// 添加一个属性来保存默认的格式
bindings.formatString = 'YYYY-MM-DD HH:mm:ss'
if (bindings.value) {
bindings.formatString = bindings.value
}
},
mounted(el, bindings) {
const textContent = el.textContent
let timestamp = parseInt(textContent)
if (textContent.length === 10) {
// 如果时间戳是以秒为单位就转化成以毫秒为单位
timestamp *= 1000
}
el.textContent = dayjs(timestamp).format(bindings.formatString)
}
}
}
}
如果自定义的指令传入了参数,那么就按照传入的参数格式来展示,如果没有传参,就按照默认的格式来展示。
全局自定义指令实现
因为上面的功能是一个公共的需求,所以应该定义为一个全局的自定义指令。
在 main.js 文件中:
import dayjs from 'dayjs'
const app = createApp(App);
app.directive("format-time", {
created(el, bindings) {
// 将初始化数据的逻辑抽取到 created 里面
bindings.formatString = 'YYYY-MM-DD HH:mm:ss'
if (bindings.value) {
bindings.formatString = bindings.value;
}
},
mounted(el, bindings) {
const textContent = el.textContent;
let timestamp = parseInt(textContent);
if (textContent.length === 10) {
// 如果时间戳是以秒为单位就转化成以毫秒为单位
timestamp *= 1000;
}
el.textContent = dayjs(timestamp).format(bindings.formatString);
},
});
抽取全局指令实现的逻辑
一、直接抽取
在 main.js 中:
import registerDirectives from "./directives/index.js";
registerDirectives(app);
在 /directives/index.js 中:
import registerFormatTime from "./format-time.js";
export default function (app) {
registerFormatTime(app);
}
在 /directives/format-time.js 中:
import dayjs from "dayjs";
export default function (app) {
app.directive("format-time", {
created(el, bindings) {
// 将初始化数据的逻辑抽取到 created 里面
bindings.formatString = 'YYYY-MM-DD HH:mm:ss'
if (bindings.value) {
bindings.formatString = bindings.value;
}
},
mounted(el, bindings) {
const textContent = el.textContent;
let timestamp = parseInt(textContent);
if (textContent.length === 10) {
// 如果时间戳是以秒为单位就转化成以毫秒为单位
timestamp *= 1000;
}
el.textContent = dayjs(timestamp).format(bindings.formatString);
},
}
在 /directives/index.js 中我们进行全局自定义指令的管理。
二、使用插件注册抽取