1.前言
在Vue中,指令是一个特殊的属性。Vue会根据不同指令,在背后执行不同的操作。
2.内置指令
截止到Vue3.2版本,Vue一共有16个内置指令,分别是:
- 1.
v-text:用于更新元素的 textContent
<div v-text="'<h2>v-text</h2>'"></div>
# 输出 <h2>v-text</h2>
- 2.
v-html:与v-text很像,只是v-html用于更新元素的 innerHTML
<div v-html="'<h2>v-html</h2>'"></div>
# 输出 v-html
# h2被渲染为了元素
- 3.
v-show:可以根据表达式的真假值,切换元素的display: block | none;值,用于控制元素的展示和隐藏
<div v-show="isShow">show</div>
<!-- 注意:v-show 不支持 <template> 元素,也不支持 v-else -->
- 4.
v-if:用于根据表达式的真假值来有条件地渲染元素。与v-show相比,v-if在切换时是元素的销毁或重建,而不是简单的显示隐藏。因此当进行高频率的显示和隐藏操作时,应该优先使用v-show
<div v-if="isShow">show</div>
- 5.
v-else:和v-if配合使用,当v-if满足条件时展示v-if的元素,否则展示v-else的元素
<div v-if="isShow">show</div>
<div v-else>hidden</div>
<!-- 注意:v-else前一个兄弟元素必须有 v-if 或 v-else-if -->
- 6.
v-else-if:和v-else一样,前一个兄弟元素必须有v-if或 v-else-if
<div v-if="isShow">show</div>
<div v-else-if="isOther">other</div>
<div v-else>hidden</div>
- 7.
v-for:一个用于迭代的指令,可以根据源数据多次渲染元素或模板块
<div v-for="item in [1, 2, 3]" :key="item">
{{item}}
</div>
- 8.
v-on:用于给元素绑定事件,可以缩写为:@。有如下的修饰符
.stop - 调用 event.stopPropagation()
.prevent - 调用 event.preventDefault()
.capture - 添加事件侦听器时使用 capture 模式
.self - 只当事件是从侦听器绑定的元素本身触发时才触发回调
.{keyAlias} - 仅当事件是从特定键触发时才触发回调,比如键盘enter键
.once - 只触发一次回调
.left - 只当点击鼠标左键时触发
.right - 只当点击鼠标右键时触发
.middle - 只当点击鼠标中键时触发
.passive - { passive: true } 模式添加侦听器
# demo:停止冒泡
<button @click.stop="doThis">Do</button>
- 9.
v-bind:用于绑定数据和元素属性,可以缩写为: 或.(当使用 .prop 修饰符时)。有如下修饰符
.camel - 将 kebab-case attribute 名转换为 camelCase
.prop - 将一个绑定强制设置为一个 DOM property。3.2+
.attr - 将一个绑定强制设置为一个 DOM attribute。3.2+
# demo
<div :someProperty.prop="someObject"></div>
# 相当于
<div .someProperty="someObject"></div>
- 10.
v-model:在表单控件或者组件上可以创建双向绑定,限制于:<input> <select> <textarea> components。有如下修饰符
.lazy - 惰性更新,监听 change 而不是 input 事件
.number - 输入字符串转为有效的数字
.trim - 输入首尾空格过滤
# demo
<input type="text" v-model="demo" />
<input type="text" v-model.lazy="demo" />
<input type="text" v-model.number="demo" />
<input type="text" v-model.trim="demo" />
<h3>{{demo}}</h3>
- 11.
v-slot:用于提供具名插槽或需要接收 prop 的插槽,可选择性传递参数,表示插槽名,默认值default
<!-- 父组件 -->
<div class="parent">
<child-item>
<p>slot展示的内容</p>
</child-item>
</div>
<!-- 子组件 -->
<div class="child">
<slot></slot>
</div>
- 12.
v-pre:用于跳过这个元素及其子元素的编译过程
<div v-pre>{{demo}}</div>
# 输出:{{demo}}
- 13.
v-cloak:用于解决插值表达式在页面闪烁问题
<div>{{demo}}</div>
<div v-cloak>{{demo}}</div>
<style>
[v-cloak] {
display: none;
}
</style>
- 14.
v-once:用于表示只渲染一次,当要重新渲染,元素/组件及其所有的子节点将被视为静态内容并跳过 - 15.
v-memo:用于缓存一个模板的子树。该指令接收一个固定长度的数组作为依赖值进行记忆比对。如果数组中的每个值都和上次渲染的时候相同,则整个该子树的更新会被跳过
<div v-memo="[valueA, valueB]"></div>
<!-- 在重新渲染时,如果 valueA 与 valueB 都维持不变,-->
<!-- 那么对这个 <div> 以及它的所有子节点的更新都将被跳过 -->
- 16.
v-is:检测动态组件。已在 3.1.0 中废弃,改用:is
<component :is="currentView"></component>
3.自定义指令
让我们先到官网简单看一下说明——vue3自定义指令,下面我们分别来创建自定义局部指令和自定义全局指令,加深对官网知识的理解。
3-1.自定义局部指令
<template>
<div class="directive">
<input type="text" v-model="inputValue" />
<br><br>
<input type="text" v-focus v-model="inputValue" />
</div>
</template>
<script>
import { defineComponent, ref } from 'vue'
export default defineComponent({
name: 'Directive',
// 自定义局部指令
directives: {
focus: {
mounted(el) {
el.focus()
},
},
},
setup() {
const inputValue = ref(null)
return {
inputValue
}
},
})
</script>
3-2.自定义全局指令
// main.js
import { createApp } from 'vue'
import App from './App.vue'
import router from './router'
const app = createApp(App)
app.directive('focus', {
// 自定义全局指令
mounted(el) {
el.focus()
}
})
app.use(router).mount('#app')
<!-- Home.vue -->
<template>
<div class="home">
<input type="text" v-model="inputValue" />
<br><br>
<input type="text" v-focus v-model="inputValue" />
</div>
</template>
<script>
import { defineComponent, ref } from 'vue';
export default defineComponent({
name: 'Home',
setup() {
const inputValue = ref(null)
return {
inputValue
}
}
});
</script>
<!-- Directive.vue -->
<template>
<div class="directive">
<input type="text" v-focus v-model="inputValue" />
<br><br>
<input type="text" v-model="inputValue" />
</div>
</template>
<script>
import { defineComponent, ref } from 'vue'
export default defineComponent({
name: 'Directive',
setup() {
const inputValue = ref(null)
return {
inputValue
}
},
})
</script>
3-3.自定义指令参数详解
通过上述例子,我们可以知道无论是使用directive自定义全局指令,还是使用directive自定义局部指令,都需要一个指令名,如focus,并且还需要mounted这类的钩子函数,以及钩子函数中的参数el。
下面说一下自定义指令中的钩子函数:
- 1.
created:在绑定元素的 attribute 或事件监听器被应用之前调用 - 2.
beforeMount:当指令第一次绑定到元素并且在挂载父组件之前调用 - 3.
mounted:在绑定元素的父组件被挂载后调用 - 4.
beforeUpdate:在更新包含组件的 VNode 之前调用 - 5.
updated:在包含组件的 VNode及其子组件的 VNode更新后调用 - 6.
beforeUnmount:在卸载绑定元素的父组件之前调用 - 7.
unmounted:当指令与元素解除绑定且父组件已卸载时,只调用一次
下面再说一下7个钩子函数中接收的4个参数:
- 1.
el:用于直接操作 DOM,表示指令绑定到的元素 - 2.
vnode:虚拟DOM,一个真实 DOM 元素的蓝图,对应el - 3.
prevNode:上一个虚拟节点 - 4.
binding对象:包含以下6个属性
instance:使用指令的组件实例
value:传递给指令的值
oldValue:先前的值
arg:传递给指令的参数
modifiers:传递给指令的修饰符
dir:一个对象,其实就是注册指令时传递的配置对象
3-4.自定义指令库的创建
关于自定义组件的相关知识已经全部介绍完毕,下面就让我们来创建一个属于自己的自定义指令库
- 1.创建一个盒子位置固定的指令:src/directives/position.js
const pos = {
mounted(el, binding) {
// 传递给指令的值:盒子是否要固定
let pinned = binding.value
// 传递给指令的修饰符:表示盒子定在哪里
let position = binding.modifiers
// 传递给指令的参数:可以表示盒子的特性
let args = binding.arg
if (pinned) {
el.style.position = 'fixed'
if (args == 'warning') {
el.style.backgroundColor = 'pink'
} else {
el.style.backgroundColor = 'gray'
}
for (let val in position) {
if (position[val]) {
el.style[val] = '10px'
}
}
} else {
el.style.position = 'static'
el.style.backgroundColor = ''
}
},
}
export default pos
- 2.创建自定义指令统一管理文件:src/directives/index.js
import pos from './position'
const directives = {
pos,
}
export default {
install(app) {
Object.keys(directives).forEach((key) => {
app.directive(key, directives[key])
})
},
}
- 3.批量注册自定义指令:src/main.js
import { createApp } from 'vue'
import App from './App.vue'
import router from './router'
import Directives from './directives/index.js'
const app = createApp(App)
app.use(Directives)
app.use(router).mount('#app')
- 4.调用全局自定义指令:src/views/Directive.vue
<template>
<div class="directive">
<div class="box" v-pos:warning.right.top="true">{{msg}}</div>
<div class="box" v-pos:normal.right.bottom="true">{{msg}}</div>
<div class="box" v-pos:normal.left.bottom="true">{{msg}}</div>
<div class="box">{{msg}}</div>
</div>
</template>
<script>
import { defineComponent, ref } from 'vue'
export default defineComponent({
name: 'Directive',
setup() {
const msg = ref('message')
return {
msg
}
},
})
</script>
<style scoped>
.box {
height: 100px;
width: 100px;
text-align: center;
line-height: 100px;
color: aliceblue;
background-color: green;
}
</style>
4.尾声
以上便是我对Vue指令知识的整理以及自己的动手实践,目前我的一个项目仓库在此 传送门,有兴趣的请点击。本期分享结束,谢谢~ 希望大家看过此文后都能拥有一套自己的自定义指定库。