介绍以及快速上手
在vue
中,我们经常会使用一些vue
指令,例如:v-model
、v-text
、v-if
等,这些都是vue
内置的指令,在这些指令之外,我们也可以自定义指令,例如:我们相对文字做一个指令,根据指令绑定的值更改文字颜色。
我们先来实现一个最简单的自定义指令:
src -> directives -> modules -> custom.ts
import { Directive } from "vue";
const custom: Directive = {
mounted(el, binding) {
el.style.color = binding.value;
}
};
export default custom;
将该指令导入到directives
文件夹的根目录 index.ts
文件下
import { App } from "vue";
import custom from "@/directives/modules/custom";
const directives = {
install(app: App<Element>) {
// 将一系列自定义指令对象安装到 Vue 应用实例中
app.directive("custom", custom);
}
};
// 导出安装函数
export default directives;
然后在main
文件引入安装函数
import { createApp } from "vue";
import App from "@/App.vue";
// 引入自定义指令
import directives from "@/directives/index";
const app = createApp(App);
app.use(directives); // 安装自定义指令
app.mount("#app");
到这里自定义指令就可以使用了,页面使用:
<template>
<div class="dc-page">
<div v-custom="'red'">文字变色</div>
</div>
</template>
解释
通过上面的例子,我们可以实现一个简单的自定义指令,步骤如下:
1、我们将自定义指令抽离出来,单独放到 directives
文件夹,并且在 directives
文件夹下,将每个指令都细分开来放到 modules
文件夹下。一个项目当中,很大可能有多个自定义指令存在,例如:按钮权限指令、角色权限指令、防抖指令等等,将这些模块独立出来方便管理。
2、在 directives
目录下的 index
定义了一个对象,内部有一个安装函数,用于管理所有的自定义指令,并将自定义指令集成到一个 install
安装函数中,然后导出该对象。
3、最后在 main
文件下引入安装函数,最后通过app.use
安装自定义指令。
接下来分别解释一下 main 文件的 app.use 以及 directives 文件(directives/index)的安装函数。
1、app.useapp.use
在官网上的解释为:安装一个插件。app.use
接收两个参数,第一个参数应是插件本身,可选的第二个参数是要传递给插件的选项。插件可以是
一个带 install() 方法的对象
,亦或直接是一个将被用作 install() 方法的函数
。插件选项 (app.use()
的第二个参数) 将会传递给插件的 install()
方法。
若 app.use()
对同一个插件多次调用,该插件只会被安装一次。
有了这个解释后,我们就知道刚才在directives文件的安装函数到底是在干什么了。
2、directives 文件(directives/index)的安装函数
在该文件下有一个 directives
对象,该对象是一个安装函数,在上面也说了,插件可以是一个带 install()
方法的对象,所以我们可以将directives
对象看成是一个插件。
在vue
官网中,插件的解释:插件 (Plugins
) 是一种能为 Vue
添加全局功能的工具代码。
一个插件可以是一个拥有 install()
方法的对象,也可以直接是一个安装函数本身。
安装函数 install()
有两个参数:app
, options
,我们在 directives
中就是利用第一个app
参数,来注册自定义指令的,这个app
就是应用实例。
注册自定义指令方法:
语法:app.directive(指令名称, 指令)
,其中,指令参数是一个指令钩子(对象),类似于vue
的生命周期。
// 指令名称、指令
// app.directive(指令名称, 指令)
app.directive('focus', {
/* ... */
})
指令钩子
const myDirective = {
// 在绑定元素的 attribute 前
// 或事件监听器应用前调用
created(el, binding, vnode) {
// 下面会介绍各个参数的细节
},
// 在元素被插入到 DOM 前调用
beforeMount(el, binding, vnode) {},
// 在绑定元素的父组件
// 及他自己的所有子节点都挂载完成后调用
mounted(el, binding, vnode) {},
// 绑定元素的父组件更新前调用
beforeUpdate(el, binding, vnode, prevVnode) {},
// 在绑定元素的父组件
// 及他自己的所有子节点都更新后调用
updated(el, binding, vnode, prevVnode) {},
// 绑定元素的父组件卸载前调用
beforeUnmount(el, binding, vnode) {},
// 绑定元素的父组件卸载后调用
unmounted(el, binding, vnode) {}
}
指令的具体细节
自定义指令有自己的生命周期钩子,一般来说,我们会在mounted
钩子中编写自定义指令。
每个钩子都有三个参数:el
, binding
, vnode
● el : 自定义指令绑定的dom
元素
● binding:自定义指令绑定的值,例如:v-text="hello"
,那么binding.value
就是"hello"
● vnode:就是vue
节点,你可以在vnode
上获取绑定的值,例如:<div v-custom="'red'" :rowData="{ id: 1, name: '三国' }">文字变色</div>
,可以使用 vnode.ctx.attrs
获取绑定的属性。
<div v-custom="'red'">文字变色</div>
自定义指令接收多个参数
binding指令参数
以数组的形式传入多个参数
<div v-custom="['red', 'cyan']">文字变色</div>
const custom: Directive = {
mounted(el, binding, vnode) {
console.log("指令参数", binding.value);
}
};
以对象的形式传入多个参数
<div
v-custom="{
textColor: 'red',
bgcColor: 'cyan'
}"
>
文字变色
</div>
const custom: Directive = {
mounted(el, binding, vnode) {
console.log("指令参数", binding.value);
}
};
vnode绑定动态参数
以v-bind
形式传入参数
<div v-custom="'red'" :rowData="{ name: '兔子先森', project: 'SnowAdmin' }">文字变色</div>
const custom: Directive = {
mounted(el, binding, vnode) {
console.log("指令参数", binding.value);
console.log("vnode", vnode.props);
}
};
自定义指令绑定函数
<template>
<div class="dc-page">
<button v-custom="getFun">文字变色</button>
</div>
</template>
<script setup lang="ts">
const getFun = () => {
console.log("这是函数");
};
</script>
const custom: Directive = {
mounted(el, binding, vnode) {
console.log("指令参数", binding.value);
}
};
既绑定参数,又绑定函数,对象、数组的形式都可以
<template>
<div class="dc-page">
<button
v-custom="{
color: 'red',
fun: getFun
}"
>
文字变色
</button>
</div>
</template>
<script setup lang="ts">
const getFun = () => {
console.log("这是函数");
};
</script>
const custom: Directive = {
mounted(el, binding, vnode) {
console.log("指令参数", binding.value);
}
};
绑定函数的注意点
自定义指令中,绑定函数后面一定不要带括号,否则会自动调用函数一次,js
中函数的调用就是函数+()
这里的表现形式也一样,另外,函数后面带了括号,自定义指令里接收的实际上是调用函数后的返回值
<template>
<div class="dc-page">
<button v-custom="getFun()">文字变色</button>
</div>
</template>
<script setup lang="ts">
const getFun = () => {
console.log("这是函数");
};
</script>
import { Directive } from "vue";
const custom: Directive = {
mounted(el, binding, vnode) {
console.log("指令参数", binding.value);
}
};
export default custom;
这里函数没有return
,所以指令参数接收的是 undefined
<template>
<div class="dc-page">
<button v-custom="getFun()">文字变色</button>
</div>
</template>
<script setup lang="ts">
const getFun = () => {
console.log("这是函数");
return "函数返回值"; // 加上返回值
};
</script>
调用函数并给函数传参
刚才说了,自定义指令不能调用函数,只能传入函数本身,那么有些事件必须调用函数传入当前row
,这种情况怎么处理呢?
这里模拟一个点击事件的监听,在点击事件中调用函数,并传入参数
<template>
<div class="dc-page">
<button
v-custom="{
goodsId: 1255,
fun: getFun
}"
>
文字变色
</button>
</div>
</template>
<script setup lang="ts">
const getFun = (e: any) => {
console.log("点击事件", e);
};
</script>
import { Directive } from "vue";
const custom: Directive = {
mounted(el, binding, vnode) {
el.__onClick__ = () => {
console.log("参数", binding.value);
let { goodsId, fun } = binding.value;
fun(goodsId);
};
// 监听绑定dom的点击事件
el.addEventListener("click", el.__onClick__);
}
};
export default custom;
上面的方法,只适合静态数据的绑定传参,如果数据是动态的,binding
是无法实时获取的,因为它在mounted
钩子中已经获取到值并绑定结束了。
<template>
<div class="dc-page">
<button
v-custom="{
goodsId: goodsId,
fun: getFun
}"
>
文字变色
</button>
</div>
</template>
<script setup lang="ts">
const goodsId = ref(100);
setTimeout(() => {
goodsId.value = 200;
}, 1000);
const getFun = (e: any) => {
console.log("点击事件", e);
};
</script>
绑定的值:goodsId
依旧是100
绑定的点击事件一定要在页面卸载前解绑
import { Directive } from "vue";
const custom: Directive = {
mounted(el, binding, vnode) {
el.__onClick__ = () => {
binding.value(vnode.props);
};
// 给dom添加点击事件,这里给el添加了一个__onClick__事件
el.addEventListener("click", el.__onClick__);
},
// 绑定元素的父组件卸载前调用
beforeUnmount(el) {
// 解绑dom上的点击事件
el.removeEventListener("click", el.__onClick__);
}
};
export default custom;
参考文献:
app.use: https://cn.vuejs.org/api/application.html#app-use
vue-插件:https://cn.vuejs.org/guide/reusability/plugins.html
自定义指令:https://cn.vuejs.org/guide/reusability/custom-directives.html...
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。