Vue 内置指令以及自定义指令
1. 内置指令
-
v-show
:- 说明:
根据条件展示元素,true展示元素,false隐藏元素
- 说明:
<template>
<div>
<button v-show="isShow"></button>
</div>
</template>
<script>
export default {
name: 'HomeView',
data() {
return {
isShow: false
};
}
};
</script>
注意:v-show 不支持写在 template
元素标签上,也不支持同时写在 v-else 标签中
v-show
是采用切换css
属性display:block
,display:none
来控制显示或隐藏dom
,所以初始页面render
时,此dom就会渲染至页面中,只不过是隐藏状态。
-
v-if
:- 说明:
根据条件展示元素,true在dom树中渲染元素,false从dom树中移除元素
- 说明:
<template>
<div>
<button v-if="isShow"></button>
</div>
</template>
<script>
export default {
name: 'HomeView',
data() {
return {
isShow: false
};
}
};
</script>
v-if
可以作用于template
中,如果表达式为true
,那么template
标签块中的代码都会渲染,反之都不渲染
v-if
也是惰性的:如果在初始渲染时条件为假,则什么也不做——直到条件第一次变为真时,才会开始渲染条件块
-
v-else
- 说明:
表示 v-if 的“else 块”
- 说明:
<template>
<div>
<button v-if="isShow">按钮1</button>
<button v-else>按钮2</button>
</div>
</template>
<script>
export default {
name: 'HomeView',
data() {
return {
isShow: false
};
}
};
</script>
v-else
元素必须紧跟在带v-if
或者v-else-if
的元素的后面,否则它将不会被识别
-
v-else-if
- 说明:
表示 v-if 的“else 块”
- 说明:
<template>
<div>
<button v-if="type === 'a'">按钮a</button>
<button v-else-if="type === 'b'">按钮b</button>
<button v-else-if="type === 'c'">按钮c</button>
<button v-else="type === 'd'">按钮d</button>
</div>
</template>
<script>
export default {
name: 'HomeView',
data() {
return {
type: 'a'
};
}
};
</script>
类似于 v-else
,v-else-if
也必须紧跟在带 v-if
或者 v-else-if
的元素之后。
-
v-bind
- 说明:
动态地绑定一个或多个 attribute,或一个组件 prop 到表达式
- 缩写:
:
- 说明:
a. 绑定一个 attribute
<template>
<div>
<img v-bind:src="imgSrc" />
<img :src="imgSrc" />
</div>
</template>
<script>
export default {
name: 'HomeView',
data() {
return {
imgSrc: 'https://picsum.photos/200/300/?random'
};
}
};
</script>
b. class 绑定
<template>
<div>
<div :class="{ red: isRed }"></div>
<div :class="[classA, classB]"></div>
<div :class="[classA, { classB: isB, classC: isC }]"></div>
</div>
</template>
<script>
export default {
name: 'HomeView',
data() {
return {
isRed: true,
classA: 'classA',
classB: 'classB',
isB: true,
isC: true
};
}
};
</script>
c. style 绑定
<template>
<div>
<div :style="{ fontSize: size + 'px' }"></div>
<div :style="[styleObjectA, styleObjectB]"></div>
</div>
</template>
<script>
export default {
name: 'HomeView',
data() {
return {
size: 20,
styleObjectA: {
color: 'red',
fontSize: '20px'
},
styleObjectB: {
color: 'blue',
fontSize: '30px'
}
};
}
};
</script>
d. 组件传值
<template>
<div>
<child-component :title="text" />
</div>
</template>
<script>
export default {
name: 'HomeView',
components: {
'child-component': {
props: {
title: String
},
template: '<div>{{ title }}</div>'
}
},
data() {
return {
text: 'test'
};
}
};
</script>
e. 传递当前所有 props
<template>
<div>
<child-component v-bind="$props" />
</div>
</template>
<script>
export default {
name: 'HomeView',
components: {
'child-component': {
props: {
title: String
},
template: '<div>{{ title }}</div>'
}
},
props: {
propsValue: String
},
data() {
return {
text: 'test'
};
}
};
</script>
-
v-text
- 说明:
更新元素的 textContent
- 说明:
<template>
<div>
<span v-text="text"></span>
<!-- 和下面的一样 -->
<span>{{ text }}</span>
</div>
</template>
<script>
export default {
name: 'HomeView',
data() {
return {
text: 'test'
};
}
};
</script>
-
v-html
- 说明:
更新元素的 innerHTML
- 版本:
vue2,vue3
- 说明:
<template>
<div>
<p v-html="innerHTML"></p>
</div>
</template>
<script>
export default {
name: 'HomeView',
data() {
return {
innerHTML: '<button>click</button>'
};
}
};
</script>
页面展示:
-
v-for
- 说明:
遍历数据
- 说明:
<template>
<div class="container">
<ul>
<li v-for="(item, index) in list" :key="item.name">{{ item.name }}{{ index }}</li>
</ul>
<ol>
<li v-for="(item, index) of list" :key="item.version">{{ item.version }}{{ index }}</li>
</ol>
</div>
</template>
<script>
export default {
name: 'HomeView',
data() {
return {
list: [
{
name: 'vue',
version: '2'
},
{
name: 'react',
version: '17'
}
]
};
}
};
</script>
注意:请不要将 v-for
与 v-if
一起使用,当和 v-if
一起使用时,v-for
的优先级比 v-if
更高,v-for
可以与 v-show
一起使用,如果需要带条件渲染,请考虑使用 computed
属性
最佳建议,在使用 v-for 时,使用 key 属性,来保证内部 diff 算法更新 dom 时最佳优化,不推荐使用 index 属性
页面展示:
-
v-model
- 说明:
在表单控件或者组件上创建双向绑定
- 说明:
<template>
<div class="container">
<p>
<span>input-</span>
<span>v-model:</span>
<span>{{ inputVal }}</span>
<input type="text" v-model="inputVal" />
</p>
<p>
<span>textarea-</span>
<span>v-model:</span>
<span>{{ textareaVal }}</span>
<textarea type="text" v-model="textareaVal"></textarea>
</p>
</div>
</template>
<script>
export default {
name: 'HomeView',
data() {
return {
inputVal: '',
textareaVal: ''
};
}
};
</script>
页面展示:
2. 自定义指令
- 注册全局指令
import Vue from 'vue';
Vue.directive('directiveName', {
bind(el, binding, vnode, oldVnode) {},
inserted(el, binding, vnode, oldVnode) {},
update(el, binding, vnode, oldVnode) {},
componentUpdated(el, binding, vnode, oldVnode) {},
unbind(el, binding, vnode, oldVnode) {}
});
<template>
<div class="container" v-directiveName></div>
</template>
- 局部注册指令
<template>
<input class="container" v-focus />
</template>
<script>
export default {
name: 'HomeView',
directives: {
focus: {
bind(el, binding, vnode, oldVnode) {},
inserted(el, binding, vnode, oldVnode) {},
update(el, binding, vnode, oldVnode) {},
componentUpdated(el, binding, vnode, oldVnode) {},
unbind(el, binding, vnode, oldVnode) {}
}
}
};
</script>
-
钩子函数
bind
: 只调用一次,指令第一次绑定到元素时调用。在这里可以进行一次性的初始化设置。inserted
: 被绑定元素插入父节点时调用 (仅保证父节点存在,但不一定已被插入文档中)。update
: 所在组件的 VNode 更新时调用,但是可能发生在其子 VNode 更新之前。指令的值可能发生了改变,也可能没有componentUpdated
: 指令所在组件的 VNode 及其子 VNode 全部更新后调用。unbind
: 只调用一次,指令与元素解绑时调用。
-
钩子函数参数
el
: 指令所绑定的元素,可以用来直接操作 DOM。binding
: 一个对象,包含以下 propertyname
: 指令名,不包括 v- 前缀。value
: 指令的绑定值,例如:v-my-directive="1 + 1" 中,绑定值为 2。oldValue
: 指令绑定的前一个值,仅在 update 和 componentUpdated 钩子中可用。无论值是否改变都可用。expression
: 字符串形式的指令表达式。例如 v-my-directive="1 + 1" 中,表达式为 "1 + 1"。arg
: 传给指令的参数,可选。例如 v-my-directive:foo 中,参数为 "foo"。modifiers
: 一个包含修饰符的对象。例如:v-my-directive.foo.bar 中,修饰符对象为 { foo: true, bar: true }。
vnode
: Vue 编译生成的虚拟节点oldVnode
: 上一个虚拟节点,仅在 update 和 componentUpdated 钩子中可用。
-
指令完整参数写法
<template>
<input v-focus:mount.foo.bar="1 + 1" />
</template>
<script>
export default {
name: 'HomeView',
directives: {
focus: {
bind(el, binding, vnode, oldVnode) {
console.log(binding);
},
inserted(el, binding, vnode, oldVnode) {},
update(el, binding, vnode, oldVnode) {},
componentUpdated(el, binding, vnode, oldVnode) {},
unbind(el, binding, vnode, oldVnode) {}
}
}
};
// [object Object]
{
"name": "focus",
"rawName": "v-focus:mount.foo.bar",
"value": 2,
"expression": "1 + 1",
"arg": "mount",
"modifiers": {
"foo": true,
"bar": true
},
"def": {}
}
</script>
- 动态参数
<template>
<input v-focus:[dynamic].foo.bar="1 + 1" />
</template>
<script>
export default {
name: 'HomeView',
data() {
return {
dynamic: [1, 2, 3, 4, 5]
};
},
directives: {
focus: {
bind(el, binding, vnode, oldVnode) {
console.log(binding);
},
inserted(el, binding, vnode, oldVnode) {},
update(el, binding, vnode, oldVnode) {},
componentUpdated(el, binding, vnode, oldVnode) {},
unbind(el, binding, vnode, oldVnode) {}
}
}
};
</script>
// [object Object]
{
"name": "focus",
"rawName": "v-focus:[dynamic].foo.bar",
"value": 2,
"expression": "1 + 1",
"arg": [
1,
2,
3,
4,
5
],
"modifiers": {
"foo": true,
"bar": true
},
"def": {}
}
- 自定义指令示例
- v-drag
<template>
<div class="container" v-drag></div>
</template>
<script>
export default {
name: 'HomeView',
data() {
return {
dynamic: [1, 2, 3, 4, 5]
};
},
directives: {
drag: {
bind(el, binding, vnode, oldVnode) {
el.onmousedown = e => {
const disX = e.clientX - el.offsetLeft;
const disY = e.clientY - el.offsetTop;
document.onmousemove = e => {
el.style.left = e.clientX - disX + 'px';
el.style.top = e.clientY - disY + 'px';
};
document.onmouseup = () => {
document.onmousemove = null;
document.onmouseup = null;
};
};
},
inserted(el, binding, vnode, oldVnode) {},
update(el, binding, vnode, oldVnode) {},
componentUpdated(el, binding, vnode, oldVnode) {},
unbind(el, binding, vnode, oldVnode) {}
}
}
};
</script>
<style scoped>
.container {
width: 500px;
height: 300px;
border: 1px solid red;
position: fixed;
left: 0;
top: 0;
}
.container:hover {
cursor: pointer;
}
</style>