Vue.js指令 (Directives) 是带有
v-
前缀的特殊特性。指令特性的值预期是单个 JavaScript 表达式 (v-for 是例外情况)。我们可以将指令看作特殊的HTML特性,作用是:当表达式的值改变时,将其产生的连带影响,响应式地作用于绑定的DOM。
内置指令指的就是Vue.js自带的指令,开箱即用,一共有14个:
该指令的作用是更新DOM元素的文本内容,使用率很低,一般都是用双花括号来代替了,可以忽略
语法如下:
<template>
<div>
<span v-text="msg"></span>
</div>
</template>
<script>
export default {
name: "home",
data() {
return {
msg: '我是一个文本信息'
}
}
}
</script>
该指令的作用是更新DOM元素的innerHTML
,内容按普通HTML插入,用处挺多的,比如渲染字符串html,动态插入元素等。(滥用可能会引起XSS攻击,比如用户提交"xxx"
,会被渲染成html标签)
语法如下:
<template>
<div>
<div v-html="span"></div>
</div>
</template>
<script>
export default {
name: "home",
data() {
return {
span: '我是span'
}
}
}
</script>
该指令不需要表达式,作用是跳过绑定了这个指令的元素和它的子元素的编译过程。跳过大量没有指令的节点会加快编译,但是绑定了后,会直接显示双花括号{{ xxx }}
,按需使用。
该指令不需要表达式。这个指令会保持在dom元素上,直到其关联的实例结束编译才失效。作用是配合css选择器[v-cloak]
,来实现隐藏未编译完成的元素,直到实例准备完毕。
语法如下:
<template>
<div>
<p v-cloak>{{ text }}</p>
</div>
</template>
<script>
export default {
name: "home",
data() {
return {
text: '这是一段text文本'
}
}
}
</script>
<style scoped>
[v-cloak] {
display: none;
}
</style>
该指令不需要表达式,作用是只渲染元素和组件一次。随后的重新渲染,元素/组件及其所有的子节点将被视为静态内容并跳过。这可以用于优化更新性能。
例子如下:
<template>
<div class="app">
<h1 v-once>{{ time }}</h1>
</div>
</template>
<script>
export default {
name: 'home',
data(){
return {
time: new Date().getTime()
}
},
mounted() {
setInterval(() => {
this.time = new Date().getTime()
}, 1000)
}
}
</script>
因为h1标签带上了v-once
指令,所以只渲染了一次,后续计时器不停修改值,也不会再渲染,显示的时间戳也就始终停在第一次。
基于源数据,多次渲染元素或模板块。数据源可以是string
、array
、object
、number
、Iterable(有迭代接口的值)
。一般v-for
会搭配内置属性key
使用,避免渲染出现问题。这也是一个经典面试题,具体原因可以看:传送门1,传送门2
例子如下:
<template>
<div class="app">
<!-- 例1 -->
<h1 v-for="(item, index) in obj" :key="index">{{item}}</h1>
<!-- 例2 -->
<h1 v-for="item in 10" :key="item">{{item}}</h1>
<!-- 例3 -->
<div v-for="item in arr" :key="item">
<span>姓名:{{item.name}}</span>
<span>年龄:{{item.age}}</span>
</div>
</div>
</template>
<script>
export default {
name: 'home',
data(){
return {
obj: {
a: 100,
b: 200,
c: 300
},
arr: [
{ name: 'x', age: 10 },
{ name: 'xx', age: 11 },
{ name: 'xxx', age: 12 }
]
}
}
}
</script>
根据表达式之真假值来渲染元素。在切换时绑定该指令的元素/组件会被销毁并重建。如果是绑定在template标签上,将提出template的内容作为条件块。
当和 v-for 一起使用时,v-for 的优先级比 v-if 更高
该指令可触发组件过渡效果
例子如下:
<template>
<div class="app">
<h1 v-if="num < 2">num小于2</h1>
<h2 v-else-if="num <= 5">num小于等于5</h2>
<h3 v-else>num大于5</h3>
</div>
</template>
<script>
export default {
name: 'home',
data(){
return {
num: Math.round(Math.random() * 10)
}
}
}
</script>
根据表达式之真假值,切换元素的CSS display
属性,当值为false时,display为none
。
该指令可触发组件过渡效果
例子如下:
<template>
<div class="app">
<h1 v-show="num < 5">我是H1</h1>
</div>
</template>
<script>
export default {
name: 'home',
data(){
return {
num: 0
}
},
mounted() {
setInterval(() => {
this.num = Math.round(Math.random() * 10)
}, 1000)
}
}
</script>
在表单控件或者组件上创建双向绑定的值,本质上来说,它是一个语法糖,它负责监听用户的输入事件以更新数据,并对一些极端场景进行一些特殊处理。比如:v-model="foo"
,等价于 :value="foo"
加上@input="foo = $event"
的便捷写法。
在大部分情况下,以下两种写法是等价的:
<input v-model="name" />
<input :value="name" @input="name = $event" />
拥有以下修饰符:
<template>
<div class="app">
<input type="text" v-model="text">
</div>
</template>
<script>
export default {
name: 'home',
data(){
return {
text: ''
}
}
}
</script>
<template>
<div>
<h1>{{ total }}</h1>
<hello-world v-model="total" @input="handleInput" />
</div>
</template>
<script>
import helloWorld from '@/components/HelloWorld'
export default {
name:'home',
components:{
helloWorld
},
data(){return {
total: 0
}},
methods: {
handleInput(v) {
this.total = v
}
}
}
</script>
value
)<template>
<div class="app">
<button @click="handleChange">增加</button>
</div>
</template>
<script>
export default {
name: 'holle',
props: ['value'],
methods: {
handleChange() {
this.$emit('input', this.value + 1)
}
}
}
</script>
<template>
<div>
<h1>{{ total }}, {{ age }}</h1>
<hello-world :a.sync="total" :b.sync="age" @input="handleInput" />
</div>
</template>
<script>
import helloWorld from '@/components/HelloWorld'
export default {
name:'home',
components:{
helloWorld
},
data(){return {
total: 0,
age: 0
}},
methods: {
handleInput(v1, v2) {
this.total = v1
this.age = v2
}
}
}
</script>
<template>
<div class="app">
<button @click="handleChange">增加</button>
</div>
</template>
<script>
export default {
name: 'holle',
props: ['a', 'b'],
methods: {
handleChange() {
this.$emit('input', this.a + 1, this.b + 2)
}
}
}
</script>
动态的绑定一个或多个属性到组件上,可以绑定class、style等任意值。可以简写为:
。拥有以下修饰符:
例子:
<template>
<div>
<h1 :class="['aaa','bbb', num < 100 ? 'ccc':'ddd']"></h1>
<h2 :style="mode"></h2>
<input type="text" :value="msg">
<img v-bind:src="imageSrc" />
</div>
</template>
<script>
export default {
name:'aaa',
data(){
return {
num: 200,
mode: {
color: 'red',
fontSize: '20px'
},
msg: '',
imageSrc: 'https://www.baidu.com/xxx.png'
}
}
}
</script>
绑定事件监听器。事件类型由参数指定。可以简写为@
。拥有以下修饰符:
<button v-on:click="add"></button>
// 动态事件
<button @[event]="change"></button>
// 事件对象
<button @click="add('hello', $event)"></button>
// 按键事件
<input @keyup.enter="onEnter" />
// 按键代码
<input @keyup.13="onEnter" />
slot,也称插槽,是组件的一块HTML模版,这块模版由父组件提供。可以说是子组件暴露的一个让父组件传入自定义内容的接口,来实现内容分发。一般都写在template
标签上,可以简写为#
。
匿名插槽用slot
标签来确定渲染的位置,里面可以放置父组件没传内容时的默认内容,一个组件里,匿名插槽只能有一个。slot="default"
可以忽略不写。
<template>
<div>
<aaaChildren></aaaChildren>
<aaaChildren>
<h1>我是父组件的内容</h1>
</aaaChildren>
</div>
</template>
<script>
import aaaChildren from './children/index.vue'
export default {
name:'aaa',
components:{
aaaChildren
}
}
</script>
<template>
<div class="aaa_children">
<slot>
<h1>我是默认内容</h1>
</slot>
</div>
</template>
<script>
export default {
name:'aaaChildren'
}
</script>
在slot
标签上加入name
属性,使得父级可以将内容插入对应的位置中。具名插槽可以有很多个,使用的时候需要带上名字做区分。
<template>
<div>
<aaaChildren>
<template #text>111</template>
<template #footer>222</template>
</aaaChildren>
</div>
</template>
<script>
import aaaChildren from './children/index.vue'
export default {
name:'aaa',
components:{
aaaChildren
}
}
</script>
<template>
<div class="aaa_children">
<slot name="text">
<h1>我是text插槽</h1>
</slot>
<div>
<slot name="footer">
<h2>我是footer插槽</h2>
</slot>
</div>
</div>
</template>
<script>
export default {
name: 'aaaChildren'
}
</script>
作用域插槽在slot
上绑定属性来将子组件的信息传给父组件使用,这些属性会被挂在父组件slot-scope接受的对象上。绑定时用的key,就是父组件获取数据的键。
<template>
<div>
<aaaChildren>
<template #default="scope">
<h1>{{ scope.info.age }}</h1>
</template>
<template #text="scope">
<h2>{{ scope.data }}</h2>
</template>
</aaaChildren>
</div>
</template>
<script>
import aaaChildren from './children/index.vue'
export default {
name:'aaa',
components:{
aaaChildren
}
}
</script>
<template>
<div class="aaa_children">
<slot :info="user"></slot>
<slot name="text" :data="name"></slot>
</div>
</template>
<script>
export default {
name:'aaaChildren',
props:[],
components:{},
data(){
return {
user: {
age: 18,
name: '小明'
},
name: '卡卡罗特'
}
}
}
</script>
自定义指令。是Vue暴漏了自定义指令的API给我们,让我们除了使用内置指令外,我们还可以自己定义指令(比如:复制粘贴指令,图片懒加载指令,防抖指令等等),定义好后和内置指令的方式非常类似。它可以有全局的和局部的两种。指令也有自己的钩子函数,如下:
以上钩子函数都有4个参数,如下:
通过Vue
实例身上的directive() API
注册一个全局自定义指令。例子如下:
/**
* 安装指令
* @param Vue vue实例
*/
export default function installDirective(Vue) {
// 粗体指令
Vue.directive('bold', {
inserted(el) {
el.style.fontWeight = 'bold'
}
})
}
directive
,然后使用Vue.use
安装指令import Vue from 'vue'
import App from './App.vue'
import initDirective from '@/directive'
Vue.use(initDirective)
new Vue({
render: h => h(App),
}).$mount('#app')
<template>
<div v-bold>123</div>
</template>
组件中也接受一个directives
的选项,在组件中定义的自定义指令,就是局部自定义指令,其参数和全局指令一致。例子如下:
<template>
<div v-bold>123</div>
</template>
<script>
export default {
name: 'aaaChildren',
directives: {
bold: {
inserted: function (el) {
el.style.fontWeight = 'bold'
}
}
}
}
</script>
指令的参数可以是动态,这样可以灵活运用,例子如下,可以动态修改高度的指令:
/**
* 安装指令
* @param Vue vue实例
*/
export default function initDirective(Vue) {
// 简写 在bind和update时触发相同行为
Vue.directive('height', (el, binding) => {
el.style.backgroundColor = 'skyblue'
el.style.height = `${binding.value}px`
})
}
<template>
<div>
<button @click="addHeight">点击增高</button>
<div v-height="h"></div>
</div>
</template>
<script>
export default {
name:'aaa',
data(){
return {
h: 100
}
},
methods: {
addHeight() {
this.h += 2
}
}
}
</script>
如果看了觉得有帮助的,我是@鹏多多,欢迎 点赞 关注 评论;
往期文章
个人主页