vue3的自定义指令详解
vue3的自定义指令详解
一、认识自定义指令
在Vue的模板语法中我们学习过各种各样的指令:v-show、v-for、v-model等等,除了使用这些指令之外,Vue也允许我们来自定义自己的指令 |
---|
- 注意:在Vue中,代码的复用和抽象
主要还是通过组件
- 通常在某些情况下,你
需要对DOM元素进行底层操作
,这个时候就会用到自定义指令
自定义指令分为两种
- 自定义
局部指令
:组件中通过directives
选项,只能在当前
组件中使用 - 自定义
全局指令
:app的 directive 方法,可以在任意
组件中被使用
比如我们来做一个非常简单的案例:当某个元素挂载完成后可以自定获取焦点
- 实现方式一:如果我们使用
默认的实现方式
<template>
<div>
<input type="text" ref="input" />
</div>
</template>
<script>
import { ref, onMounted } from "vue";
export default {
setup () {
const input = ref(null);
onMounted(() => {
input.value.focus();
})
return {
input
}
}
}
</script>
<style scoped>
</style>
- 实现方式二:自定义一个
v-focus 的局部指令
<template>
<div>
<input type="text" v-focus>
</div>
</template>
<script>
export default {
// 局部指令
directives: {
focus: {
mounted(el, bindings, vnode, preVnode) {
console.log("focus mounted");
el.focus();
}
}
}
}
</script>
<style scoped>
</style>
- 实现方式三:自定义一个
v-focus 的全局指令
app.directive("focus", {
mounted(el, bindings, vnode, preVnode) {
console.log("focus mounted");
el.focus();
}
})
二、指令的生命周期
一个指令定义的对象,Vue提供了如下的几个钩子函数
- created:在绑定元素的 attribute 或事件监听器被应用之前调用;
- beforeMount:当指令第一次绑定到元素并且在挂载父组件之前调用;
- mounted:在绑定元素的父组件被挂载后调用;
- beforeUpdate:在更新包含组件的 VNode 之前调用;
- updated:在包含组件的 VNode 及其子组件的 VNode 更新后调用;
- beforeUnmount:在卸载绑定元素的父组件之前调用;
- unmounted:当指令与元素解除绑定且父组件已卸载时,只调用一次;
<template>
<div>
<button v-if="counter < 2" v-why @click="increment">当前计数: {{counter}}</button>
</div>
</template>
<script>
import { ref } from "vue";
export default {
// 局部指令
directives: {
why: {
created(el, bindings, vnode, preVnode) {
console.log("why created", el, bindings, vnode, preVnode);
console.log(bindings.value);
console.log(bindings.modifiers);
},
beforeMount() {
console.log("why beforeMount");
},
mounted() {
console.log("why mounted");
},
beforeUpdate() {
console.log("why beforeUpdate");
},
updated() {
console.log("why updated");
},
beforeUnmount() {
console.log("why beforeUnmount");
},
unmounted() {
console.log("why unmounted");
}
}
},
setup() {
const counter = ref(0);
const increment = () => counter.value++;
return {
counter,
increment
}
}
}
</script>
<style scoped>
</style>
三、指令的参数和修饰符
- 如果我们指令
需要接受一些参数或者修饰符应该如何操作呢?
- info是参数的名称
- aaa-bbb是修饰符的名称
- 后面是传入的具体的值
- 在我们的生命周期中,我们可以
通过 bindings 获取到对应的内容
四、自定义指令练习
- 自定义指令案例:时间戳的显示需求
- 在开发中,大多数情况下从
服务器
获取到的都是时间戳
- 我们需要
将时间戳转换成具体格式化的时间
来展示 - 在
Vue2
中我们可以通过过滤器
来完成 - 在Vue3中我们可以通过
计算属性(computed)
或者自定义一个方法(methods)
来完成 - 其实我们还可以
通过一个自定义的指令来完成
- 我们来实现一个可以
自动对时间格式化的指令v-format-time
- 这里我们封装了一个函数,在首页中我们只需要调用这个函数并且传入app即可
目录结构
format-time.js
import dayjs from 'dayjs';
export default function(app) {
app.directive("format-time", {
created(el, bindings) {
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 = timestamp * 1000
}
el.textContent = dayjs(timestamp).format(bindings.formatString);
}
})
}
index.js
import registerFormatTime from './format-time';
export default function registerDirectives(app) {
registerFormatTime(app);
}
App.vue
<template>
<h2 v-format-time="'YYYY/MM/DD'">{{timestamp}}</h2>
<h2 v-format-time>{{timestamp}}</h2>
<h2 v-format-time>{{timestamp}}</h2>
<h2 v-format-time>{{timestamp}}</h2>
<h2 v-format-time>{{timestamp}}</h2>
<h2 v-format-time>{{timestamp}}</h2>
</template>
<script>
export default {
setup() {
const timestamp = 1624452193;
return {
timestamp
}
},
mounted() {
console.log("app mounted");
}
}
</script>
<style scoped>
</style>
main.js
import { createApp } from 'vue'
import App from './03_自定义指令/App.vue'
import registerDirectives from './directives'
const app = createApp(App);
registerDirectives(app);
app.mount('#app');