指令带有前缀 v-,以表示它们是 Vue 提供的特殊特性,它们会在渲染的 DOM 上应用特殊的响应式行为。
一、文本指令
- v-cloak:保持在元素上直到关联实例结束编译
<style>
[v-cloak]{
display: none;
}
</style>
<p v-cloak>{{ message }}</p>
和 CSS 规则如 [v-cloak] { display: none } 一起用时,这个指令可以隐藏未编译的 Mustache 标签直到实例准备完毕,即解决网速慢时文本显示的闪烁问题。
- v-text:更新元素的 textContent
<p v-text="message">Overwritten content</p>
v-text 指令会覆盖元素的 textContent,如果要更新部分的 textContent ,需要使用 {{ Mustache }} 插值。
- v-html:更新元素的 innerHTML
<div id="app" v-html="html_msg">
<p>Overwritten content</p>
</div>
<script>
var app = new Vue({
el: '#app',
data: {
message: 'Hello Vue!',
html_msg: '<p>Hello Vue</p>'
},
})
</script>
</body>
</html>
类似地,v-html 指令会覆盖元素的 innerHTML。
二、绑定指令
1、v-bind:
动态地绑定一个或多个特性,或一个组件 prop 到表达式。
<div id="app">
<!-- 绑定一个属性 -->
<input type="button" value="button1" v-bind:title="myTitle">
<!-- 缩写形式:用 ":" 代替 "v-bind:" -->
<input type="button" value="button2" :title="myTitle">
<!-- 内联字符串拼接 -->
<input type="button" value="button3" :title="myTitle + '123'">
</div>
<script>
var app = new Vue({
el: '#app',
data: {
myTitle:"This is my title."
}
})
</script>
修饰符:
- .prop - 被用于绑定 DOM 属性 (property);
- .camel - (2.1.0+) 将 kebab-case 特性名转换为 camelCase;
- .sync (2.3.0+) 语法糖,会扩展成一个更新父组件绑定值的 v-on 侦听器。
(1)绑定class样式
在绑定class样式时,可以使用数组,也可以使用对象。
i、使用数组:
- 数组中可以直接引用样式名称,但是名称要加上单引号,否则会被认为是变量;
- 数组中也可以嵌套对象;
- 在数组中还可以使用三元表达式,以便利用变量控制样式的显示。
ii、使用对象:
- 在使用对象时,属性名称为样式名,属性值为控制显示的布尔值。
iii、示例:
<style>
.red {
color: red;
}
.thin {
font-weight: 200;
}
.italic {
font-style: italic;
}
</style>
<div id="app">
<!--数组中使用三元表达式-->
<h1 :class="['red', 'thin', flag?'italic':'']">This is a paragraph of text1.</h1>
<!--数组中使用对象-->
<h1 :class="['red', 'thin', {italic:flag}]">This is a paragraph of text2.</h1>
<!--使用对象-->
<h1 :class="classObj">This is a paragraph of text3.</h1>
</div>
<script>
var vm = new Vue({
el: "#app",
data: {
flag: false,
classObj: {red: true, thin: true, italic: false}
}
})
</script>
(2)绑定内联样式
类似地,在绑定 style 样式时,可以使用数组,也可以使用对象。对象的属性名称为内联样式名称,属性值为内联样式值,属性需要加上引号。
<div id="app">
<!--使用对象-->
<h1 :style="styleObj2">This is a paragraph of text1.</h1>
<!--使用数组,数组中元素为对象-->
<h1 :style="[styleObj1, styleObj2]">This is a paragraph of text2.</h1>
</div>
<script>
var vm = new Vue({
el: "#app",
data: {
styleObj1: {color: 'red', 'font-weight': 200},
styleObj2: {'font-style': 'italic'}
}
})
</script>
2、v-on:
绑定事件监听器,事件类型由参数指定,表达式可以是一个方法的名字或一个内联语句,如果没有修饰符也可以省略。
<div id="app">
<!-- 绑定点击事件 -->
<input type="button" value="button1" v-on:click="show">
<!-- 缩写形式:用 "@" 代替 "v-on:" -->
<input type="button" value="button2" @click="show">
</div>
<script>
var app = new Vue({
el: '#app',
methods: {
show: function(){
alert("Hello World!");
}
}
})
</script>
修饰符:
- .stop - 调用 event.stopPropagation();
- .prevent - 调用 event.preventDefault();
- .capture - 添加事件侦听器时使用 capture 模式;
- .self - 只当事件是从侦听器绑定的元素本身触发时才触发回调;
- .{keyCode | keyAlias} - 只当事件是从特定键触发时才触发回调;
- .native - 监听组件根元素的原生事件;
- .once - 只触发一次回调;
- .left - (2.2.0) 只当点击鼠标左键时触发;
- .right - (2.2.0) 只当点击鼠标右键时触发;
- .middle - (2.2.0) 只当点击鼠标中键时触发;
- .passive - (2.3.0) 以 { passive: true } 模式添加侦听器。
3、v-model:
在表单控件(input、select、textarea…)或者组件上创建双向绑定。
<div id="app">
<p>{{msg}}</p>
<!--在修改text输入框值时,msg同步修改-->
<input type="text" v-model="msg">
</div>
<script>
var app = new Vue({
el: '#app',
data: {
msg: "This is a message."
}
})
</script>
修饰符:
- .lazy - 取代 input 监听 change 事件;
- .number - 输入字符串转为有效的数字;
- .trim - 输入首尾空格过滤。
三、流程指令
1、v-for:
基于源数据多次渲染元素或模板块,即对元素进行循环或迭代。此指令之值,必须使用特定语法 alias in expression ,为当前遍历的元素提供别名。
(1)循环普通数组
<div v-for="item in items">
{{ item }}
</div>
(2)循环对象数组
<div v-for="item in items">
{{ item.text }}
</div>
(3)循环对象
<div v-for="(value,key) in items">
{{ item.key}}--{{ item.value}}
</div>
(4)迭代数字
<div v-for="count in 5">
{{ count }}
</div>
(5)key 属性
当 Vue 正在更新使用 v-for 渲染的元素列表时,它默认使用“就地更新”的策略。如果数据项的顺序被改变,Vue 将不会移动 DOM 元素来匹配数据项的顺序,而是就地更新每个元素,并且确保它们在每个索引位置正确渲染。
这个默认的模式是高效的,但是只适用于不依赖子组件状态或临时 DOM 状态 (例如:表单输入值) 的列表渲染输出。
为了给 Vue 一个提示,以便它能跟踪每个节点的身份,从而重用和重新排序现有元素,你需要为每项提供一个唯一 key 属性(string / number 类型):
<div v-for="item in items" :key="item.id">
{{ item.text }}
</div>
(6)示例代码
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
<script src="../vue.min.js"></script>
</head>
<body>
<div id="app">
<p>1、循环普通数组</p>
<p v-for="item in list1">{{item}}</p>
<p>2、循环对象数组</p>
<p v-for="(item, i) in objList">{{i}}--{{item.name}}--{{item.age}}</p>
<p>3、循环对象</p>
<p v-for="(value, key, i) in obj">{{i}}--{{key}}--{{value}}</p>
<p>4、迭代数字</p>
<p v-for="count in 5">第{{count}}次计数</p>
</div>
<script>
var vm = new Vue({
el: "#app",
data: {
list1: [1, 2, 3, 4],
objList: [{name: 'Tom', age: 20}, {name: 'Alice', age: 19}],
obj: {
name: "Sam",
age: 20,
tel: '123456'
}
}
})
</script>
</body>
</html>
2、v-show:
根据表达式之真假值,切换元素的 display CSS 属性。所以,它有较高的初始渲染消耗,如果元素涉及到频繁的切换,则推荐使用 v-show。
<p v-show="flag">content</p>
3、v-if:
根据表达式的值的真假条件渲染元素,在切换时元素及它的数据绑定 / 组件被销毁并重建。所以, v-if 有较高的切换性能消耗,如果元素很大概率不会被渲染或重复渲染,则推荐使用 v-if 。
<p v-if="flag">content</p>
4、v-else:
v-else ,表示 v-if 的“else 块”,v-else 元素必须紧跟在带 v-if 或者 v-else-if 的元素的后面,否则它将不会被识别。
<div v-if="Math.random() > 0.5">
Now you see me
</div>
<div v-else>
Now you don't
</div>
5、v-else-if:
v-else-if,充当 v-if 的“else-if 块”,可以连续使用。类似于 v-else,v-else-if 也必须紧跟在带 v-if 或者 v-else-if 的元素之后。
<div v-if="type === 'A'">
A
</div>
<div v-else-if="type === 'B'">
B
</div>
<div v-else-if="type === 'C'">
C
</div>
<div v-else>
Not A/B/C
</div>
四、自定义指令
除了核心功能默认内置的指令,Vue 也允许注册自定义指令。
1、注册指令
(1)注册或获取全局指令
// 注册
// {string} id 注册指令的名称
// {Function | Object} [definition] 属性为钩子函数的对象
Vue.directive('my-directive', {
bind: function () {},
inserted: function () {},
update: function () {},
componentUpdated: function () {},
unbind: function () {}
})
// 注册 简写形式 默认被 `bind` 和 `update` 调用
Vue.directive('my-directive', function () {
})
// getter,返回已注册的指令
var myDirective = Vue.directive('my-directive')
- 使用示例:
<div id="app">
<input type="text" v-focus>
</div>
<script>
// 自定义全局获取焦点指令
Vue.directive('focus', {
inserted: function (el) {
el.focus()
},
update: function () {console.log("222");},
})
// 注意:只有在Vue实例控制区域内,才能使用指令
var vm = new Vue({
el: "#app"
})
</script>
(2)注册局部指令
var vm = new Vue({
directives: {
my-directive: {
bind: function () {},
...
}
}
}
- 使用示例:
<div id="app">
<input type="text" v-focus>
</div>
<script>
var vm = new Vue({
el: "#app",
directives: {
// 自定义局部获取焦点指令
focus: {
inserted: function (el) {
el.focus();
},
}
}
})
</script>
2、钩子函数
(1)钩子函数
一个指令定义对象可以提供如下几个钩子函数 (均为可选):
-
bind:只调用一次,指令第一次绑定到元素时调用。在这里可以进行一次性的初始化设置。
-
inserted:被绑定元素插入父节点时调用 (仅保证父节点存在,但不一定已被插入文档中)。
-
update:所在组件的 VNode 更新时调用,但是可能发生在其子 VNode 更新之前。
-
componentUpdated:指令所在组件的 VNode 及其子 VNode 全部更新后调用。
-
unbind:只调用一次,指令与元素解绑时调用。
(2)钩子函数参数
- el:指令所绑定的元素,可以用来直接操作 DOM 。
- binding:一个对象,包含以下属性:
- name:指令名,不包括 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 钩子中可用。
综合案例
- 走马灯效果
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
<script src="./vue.min.js"></script>
</head>
<body>
<div id="app">
<input type="button" value="浪起来" @click="lang">
<input type="button" value="低调" @click="stop">
<h4>{{msg}}</h4>
</div>
<script>
var vm = new Vue({
el: "#app",
data: {
msg: "猥琐发育,别浪~",
intervalId: null
},
methods: {
lang: function(){
// 定时器已开启,则直接返回
if(this.intervalId != null) return;
// 在定时器中,将字符串的第一个字符放到最后
this.intervalId = setInterval(() => {
var start = this.msg.substring(0,1);
var end = this.msg.substring(1);
this.msg = end + start;
}, 400);
},
stop: function(){
clearInterval(this.intervalId);
// 清除定时器的开启状态
this.intervalId = null;
}
}
})
</script>
</body>
</html>
- 简易计算器
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
<script src="./vue.min.js"></script>
</head>
<body>
<div id="app">
<input type="text" v-model="num1">
<select v-model="opt">
<option value="+">+</option>
<option value="-">-</option>
<option value="*">*</option>
<option value="/">/</option>
</select>
<input type="text" v-model="num2">
<input type="button" value="=" @click="calc"></button>
<input type="text" v-model="result">
</div>
<script>
var vm = new Vue({
el: "#app",
data: {
num1: 0,
num2: 0,
result: 0,
opt: "+"
},
methods: {
calc: function(){
this.result = eval("parseInt(this.num1)" + this.opt + "parseInt(this.num2)");
}
}
})
</script>
</body>
</html>
- 商品管理案例:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
<script src="../vue.min.js"></script>
<link href="https://cdn.staticfile.org/twitter-bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet">
</head>
<body>
<div id="app">
<div class="panel panel-primary">
<div class="panel-heading">
<h3 class="panel-title">添加品牌</h3>
</div>
<div class="panel-body form-inline">
<label>
Id:
<input type="text" class="form-control" v-model="id">
</label>
<label>
<!-- 注册键盘回车事件 -->
Name:
<input type="text" class="form-control" v-model="name" @keyup.enter="add">
</label>
<input type="button" value="添加" class="btn btn-primary" @click="add">
<label>
搜索名称关键字:
<input type="text" class="form-control" v-model="keywords" v-focus>
</label>
</div>
</div>
<table class="table table-bordered table-hover table-striped">
<thead>
<tr>
<th>Id</th>
<th>Name</th>
<th>Ctime</th>
<th>Operation</th>
</tr>
</thead>
<tbody v-for="item in search(keywords)" :key="item.id">
<tr>
<td>{{ item.id }}</td>
<td>{{ item.name }}</td>
<td>{{ item.ctime | dateFormat }}</td>
<td>
<!-- 阻止默认行为 -->
<a href="" @click.prevent="del(item.id)">删除</a>
</td>
</tr>
</tbody>
</table>
</div>
<script>
// 注意:全局过滤器必须定义在要使用的Vue实例前
Vue.filter('dateFormat', function(dateStr){
var dt = new Date(dateStr);
var y = dt.getFullYear();
var m = (dt.getMonth() + 1).toString().padStart(2, '0');
var d = dt.getDate().toString().padStart(2, '0');
return y + '-' + m + '-' + d
});
Vue.directive('focus', {
inserted: function (el) {
el.focus()
}
})
var vm = new Vue({
el: "#app",
data: {
id: '',
name: '',
keywords: '',
list: [
{id: 1, name: '奔驰', ctime: new Date()},
{id: 2, name: '宝马', ctime: new Date()},
{id: 3, name: '五菱', ctime: new Date()},
]
},
methods: {
add: function(){
var car = {id: this.id, name: this.name, ctime: new Date()}
this.list.push(car)
this.name = this.id = ''
},
del: function(id){
this.list.some((item, i) => {
if(item.id == id){
this.list.splice(i, 1)
return true
}
})
},
search: function(keywords){
var newlist = []
this.list.forEach(item => {
if(item.name.indexOf(keywords) != -1){
newlist.push(item);
}
});
return newlist;
}
},
})
</script>
</body>
</html>
参考链接: