本文承接上文,继续对Vue的指令进行介绍,建议读者先阅读上篇文章,以免有不解之处。前文请参考“Vue学习——指令(一)”
内置指令
v-for
3. 过滤和排序
有时想要显示一个数组经过过滤或排序后的版本,但不实际改变或重置原始数据。在这种情况下,可以创建一个计算属性,来返回过滤或排序后的数据。
代码示例如下
<li v-for="n in evenNumbers">{{n}}</li>
data: {
numbers: [1, 2, 3, 4, 5]
},
computed: {
evenNumbers: function() {
return this.numbers.filter(function(number) {
return number % 2 === 0
})
}
}
在计算属性不适用的情况下(例如,在嵌套v-for循环中),也可以使用一个方法。
<li v-for="n in even(numbers)">{{n}}</li>
data: {
numbers: [1, 2, 3, 4, 5]
},
computed: {
even: function(numbers) {
return this.numbers.filter(function(number) {
return number % 2 === 0
})
}
}
4. 遍历整数
v-for指令也可以接受整数。在这种情况下,它会把模版重复对应次数。
代码示例如下
<div>
<span v-for="n in 10">{{n}}</span>
</div>
输出内容如下图所示:
5. v-for遍历对象
遍历对象的语法形式和遍历数组是一样的,即value in object,其中object是被迭代的对象,value是被迭代的对象属性的别名。
代码示例如下
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title></title>
</head>
<body>
<div id="app">
<ul>
<li v-for='value in book'>{{value}}</li>
</ul>
</div>
<script src="vue.js"></script>
<script>
var vm = new Vue({
el: '#app',
data: {
book: {
title: 'Book',
author: 'John',
isbn: '1234567890'
}
}
})
</script>
</body>
</html>
渲染后的结果如下图所示:
如果要获取对象的属性名,可以使用可选的属性名参数(也就是键名)作为第二个参数。
修改代码中的<li>元素
<li v-for="(value, key) in book">{{key}} : {{value}}</li>
遍历对象的表达式中还可以使用第三个参数作为索引
<li v-for="(value, key, index) in book">{{index}}. {{key}} : {{value}}</li>
最终的渲染结果如下图所示:
6. 对象更新检测
由于JavaScript的限制,Vue不能检测对象属性的添加和删除。要解决这个问题,只能使用Vue全局的set()和delete()方法,或者通过Vue实例的delete()方法来执行属性的操作,并触发视图更新。
代码示例如下
// 使用Vue的全局set()方法添加属性
Vue.set(vm.book, 'publishDate', '2020-8-27')
// 使用Vue实例的$set()方法添加属性
vm.$set(vm.book, 'publishDate', '2020-8-27')
// 使用Vue的全局delete()方法删除属性
Vue.delete(vm.book, 'isbn')
// 使用Vue实例的$delete()方法删除属性
vm.$delete(vm.book, 'isbn')
7. 在<template>上使用v-for
类似于v-show和v-if,也可以利用带有v-for指令的<template>来循环渲染一段包含多个元素的内容。
代码示例如下
<ul>
<template v-for="item in items">
<li>{{item.msg}}<li>
<li>{{item.code}}<li>
</template>
</ul>
8. key属性
先来看这段代码
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title></title>
</head>
<body>
<div id="app">
<p>
ID: <input type="text" v-model="bookId">
书名: <input type="text" v-model="title">
<button v-on:click="add()">添加</button>
</p>
<p v-for="book in books">
<input type="checkbox">
<span>ID: {{book.id}} , 书名: {{book.title}}</span>
</p>
</div>
<script src="vue.js"></script>
<script>
var vm = new Vue({
el: '#app',
data: {
bookId: '',
title: '',
books: [
{id: 1, title: 'book1'},
{id: 2, title: 'book2'},
{id: 3, title: 'book3'}
]
},
methods: {
add() {
this.books.unshift({
id : this.bookId,
title : this.title
})
this.bookId = '',
this.title = ''
}
}
})
</script>
</body>
</html>
这段代码预先定义了一个books数组对象,通过v-for指令遍历该数组,同时提供了两个输入框,在用户输入了图书的ID和书名后,向数组中添加一个新的图书对象。我们使用的是数组的unshift()方法,该方法向数组的开头添加一个或多个元素。
使用浏览器打开该页面,将显示如下画面:
向列表中输入内容并点击添加按钮,画面更新如下所示:
这时我们发现一个问题,之前选中的id为1的图书,在我们添加新图书后,选中指向不正确。
而产生这个问题的原因是:当Vue正在更新使用v-for渲染的元素列表时,它默认使用“就地更新”策略。如果数据项的顺序被改变,Vue将不会移动DOM元素来匹配数据项的顺序,而是就地更新每个元素,并且确保它们在每个索引位置正确渲染。
在本例中,当勾选id:1的书籍时,指令只记住了勾选的数组下标为0,当数组更新后,虽然数组长度发生了变化,但是指令只记得你当时勾选的数组下标,于是添加新元素后,显示的勾选就变成了id:5的书籍。
为了给Vue一个提示,以便它能够跟踪每个节点的身份,从而重用和重新排序现有元素,需要为列表的每一项提供一个唯一key属性。key属性的类型只能是string或者number类型。
修改上述代码,在v-for指令后添加key属性
<p v-for="book in books" v-bind:key="book.id">
在浏览器中刷新页面,再次执行之前的操作,结果显示将如下图所示:
9. v-for-v-if
当v-for与v-if一起使用时,v-for的优先级比v-if要高,这意味着v-if将分别重复运行于每个v-for循环中。如果在渲染一个列表时,对列表的某些项需要根据条件来判断是否渲染,那么就可以使将v-for和v-if联合一起使用。
代码示例如下
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title></title>
</head>
<body>
<div id="app">
<h1>已完成的工作计划</h1>
<ul>
<li v-for="plan in plans" v-if="plan.isComplete">
{{plan.content}}
</li>
</ul>
<h1>未完成的工作计划</h1>
<ul>
<li v-for="plan in plans" v-if="!plan.isComplete">
{{plan.content}}
</li>
</ul>
</div>
<script src="vue.js"></script>
<script>
var vm = new Vue({
el: '#app',
data: {
plans: [
{content: 'planA', isComplete: false},
{content: 'planB', isComplete: true},
{content: 'planC', isComplete: false},
{content: 'planD', isComplete: true},
{content: 'planE', isComplete: false}
]
}
})
</script>
</body>
</html>
渲染结果如下图所示:
如果仅仅是要根据某个条件的真假来决定是否跳过整个循环的执行,那么可以将v-if置于外层元素(或<template>)上
<ul v-if="plans.length">
<li v-for="plan in plans">
{{plan.content}}
</li>
</ul>
<p v-else>没有工作计划</p>
v-bind
v-bind指令在之前已经进行了初步介绍,主要用于响应更新HTML元素的属性,将一个或多个属性或者一个组件的prop动态绑定到表达式。
代码示例如下
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title></title>
</head>
<body>
<div id="app">
<!-- 绑定一个属性 -->
<img v-bind:src="imgSrc">
<!-- 缩写 -->
<img :src="imgSrc">
<!-- 动态属性名(2.6.0+) -->
<a v-bind:[attrname]="url">链接</a>
<!-- 内联字符窜拼接 -->
<img :src="'images/' + fileName">
</div>
<script src="vue.js"></script>
<script>
var vm = new Vue({
el: '#app',
data: {
attrname: 'href',
url: 'http://www.sina.com.cn/',
imgSrc: 'images/bg.jpg',
fileName: 'bg.jpg'
}
})
</script>
</body>
</html>
v-bind指令还可以直接绑定一个有属性的对象
<div id="app">
<form v-bind="formObj">
<input type="text">
</form>
</div>
<script src="vue.js"></script>
<script>
var vm = new Vue({
el: '#app',
data: {
formObj: {
method: 'get',
action: '#'
}
}
})
</script>
v-model
v-model指令用来在表单<input>、<textarea>及<select>元素上创建双向数据绑定,它会根据控件类型自动选取正确的方法来更新元素。v-model本质上是“语法糖”,它负责监听用户的输入事件以更新数据,并对一些极端场景进行特殊处理。
语法糖(Syntactic sugar),也译为糖衣语法,是由英国计算机科学家彼得·约翰·兰达(Peter J.Landin)发明的一个术语,指计算机语言中添加的某种语法,这种语法对语言的功能并没有影响,但是更方便程序员使用。通常来说语法糖能够增加程序的可读性,从而减少程序代码出错的机会。
v-model代码示例如下
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title></title>
</head>
<body>
<div id="app">
<input type="text" v-model="message">
</div>
<script src="vue.js"></script>
<script>
var vm = new Vue({
el: '#app',
data: {
message: 'Hello World'
}
})
</script>
</body>
</html>
使用浏览器打开该页面,可以看到文本输入空间中的内容为Hello World,这时在Console窗口中输入以下内容:
vm.message = "Welcome you"
可以看到输入控件中的内容也发生了改变,如下图所示:
接下来在输入控件中随意输入些内容,在Console窗口中输入下面的内容:
vm.message
可以看到message的值也发生了变化,如下图所示:
关于v-model的用法还有更多内容,不在本文更多赘述了,在后续介绍Vue表单控件时会进行相应的补充。
由于篇幅有限,本篇文章就先介绍到这里,其余指令将在下篇文章继续介绍。后续更多内容请参考“Vue学习——指令(三)”