如何定义自定义指令
从一个小需求入手,如果我们想在一个页面挂载完成后,指定一个input自动获取焦点。
不使用自定义指令实现
代码:
<template>
<div>
<!-- vue在遇到ref这个属性的时候会进行特殊处理,不需要用:绑定 -->
<input type="text" ref="input">
</div>
</template>
<script>
import { ref, onMounted } from 'vue';
export default {
setup(){
const input = ref(null);
onMounted(() => {
console.log(input.value);
//获取焦点
input.value.focus();
})
return{
input
}
}
}
</script>
<style scoped>
</style>
首先我们需要使用ref获取对应的input元素,然后在挂载完成后的生命周期中将这个input元素使用 focus() 获取焦点。
这个写法有一个问题,就是如果我们的项目中很多的页面都需要这个功能,我们就需要,重复书写这个逻辑。
定义局部指令
代码:
<template>
<div>
<!-- 实现一个v-focus,实现自动获取焦点 -->
<input type="text" v-focus>
</div>
</template>
<script>
export default {
//局部指令
directives:{
//使用时自动加上v-
focus: {
//mounted生命周期时的指令
//vue在进行挂载后会回调这个函数
mounted(el, bindings, vnode, preVnode) {
console.log("focus mounted");
el.focus();
}
}
}
}
</script>
<style scoped>
</style>
我们可以在对应组件中,在directives中定义一个v-focus指令, 指令对象中可以定义多个生命周期函数,我们在挂载后(mounted)的生命周期函数会被回调,执行获取焦点操作。
定义全局指令
代码:
import { createApp } from 'vue'
import App from './自定义指令/App.vue';
const app = createApp(App).mount('#app')
// 全局指令
app.directive("focus", {
mounted(el, bindings, vnode, preVnode){
console.log("focus mounted");
el.focus();
}
})
我们也可以直接在vue文件的出口函数中定义全局指令,这样所有的vue组件都可以使用该命令。
指令的生命周期
一个指令定义的对象中,vue提供了如下几个生命周期的钩子
- created:在绑定的元素的attribute 或 事件监听器被应用 或 其他属性还未绑定之前调用。主要在这里做一些初始化操作。
- beforeMount:当指令第一次绑定到元素并且在挂载父组件之前被调用。
- mounted: 当绑定元素的父组件被挂载之后调用。
- beforeUpdate:在更新包含组件的VNode之前调用。
- update:在包含组件的VNode及其子组件的VNode更新后调用。
- beforeUnmount:在卸载绑定元素的父组件之前调用;
- unmounted:当指令与元素解绑且元素父组件已卸载时,只调用一次。
关于自定义组件传参
实现时间戳转换为固定格式时间
组件的vue代码:
<template>
<div>
<h2 v-format-time="'YYYY/MM/DD HH:mm:ss'">{{time}}</h2>
</div>
</template>
<script>
export default {
setup(){
return{
time: 1675623235,
}
}
}
</script>
<style scoped>
</style>
指令的创建代码:
import dayjs, { Dayjs } from "dayjs";
export default function(app){
//时间格式
let timeFormat = "YYYY-MM-DD HH:mm:ss";
//定义指令
app.directive("format-time", {
created(el, bindings){
if(bindings.value){
timeFormat = bindings.value ;
}
},
mounted(el){
const textContent = el.textContent;
let timeStamp = parseInt(el.textContent);
if(textContent.length == 10){
timeStamp *= 1000;
}
el.textContent = dayjs(timeStamp).format(timeFormat);
}
});
}
我们在v-format-time指令传入参数,表示时间的格式,
指令中,通过bindings对象参数的value值,即bingings.value取出时间格式,根据传参的参数决定代码逻辑。