第五章 内置指令
5.1 基本指令
5.1.1 v-cloak
不需要表达式,会在Vue实例结束编译时从绑定的HTML元素上移除,经常和CSS的display:none配合使用。当网速较慢,Vue.js文件还没加载完是,页面上会显示{{message}}字样。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>5.1 .1 v-cloak</title> </head> <style type="text/css"> [v-cloak] { display: none; } </style> <body> <div id="app" v-cloak> {{message}} </div> <script src="../vue.min.js"></script> <script type="application/javascript"> //延迟2秒后显示 setTimeout(() => { new Vue({ el: "#app", data: { message: "这是文本内容!" } }) }, 2000); </script> </body> </html>
5.1.2 v-once
不需要表达式,用途:定义它的元素或组件只渲染一次,包括元素或组件的所有子节点,首次渲染后,不再随数据的变化重新渲染,将视为静态内容。
5.2 条件渲染指令
5.2.1 v-if、v-else-if、v-else
vue条件指令可以根据表达式的值,在DOM中渲染或销毁元素/组件
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>5.2.1 v-if、v-else-if、v-else</title> </head> <body> <div id="app"> <p v-if="status===1">当status为1时显示该行</p> <p v-else-if="status===2">当status为2时显示该行</p> <p v-else="status===1">否则显示该行</p> </div> <script src="../vue.min.js"></script> <script type="application/javascript"> var app=new Vue({ el:"#app", data:{ status:1 } }) </script> </body> </html>
在渲染时,处于效率考虑,会尽可能复用已有的元素而非重新渲染,如果希望每次都重新渲染,可以提供key属性,key的值必须唯一。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>5.2.1 v-if、v-else-if、v-else</title> </head> <body> <div id="app"> <template v-if="type === 'name'"> <label for="">用户名:</label> <input type="text" placeholder="输入用户名"> </template> <template v-else> <label for="">邮箱:</label> <input type="text" placeholder="输入邮箱"> </template> <button @click="handleToggleClick">切换输入类型</button> </div> <script src="../vue.min.js"></script> <script type="application/javascript"> var app = new Vue({ el: "#app", data: { type: "name" }, methods: { handleToggleClick: function () { this.type = this.type == 'name' ? 'mail' : 'name'; } } }) </script> </body> </html>
如果一次性判断的是多个元素,可以在Vue.js内置的<template>元素上使用条件指令
5.2.2 v-show
用法与v-if类似,作用是改变元素的css属性display,当v-show表达式值为false时,元素会隐藏。即display:none。但v-show不能用于内置<template>
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>v-show</title> </head> <body> <div id="app"> <p v-show="status === 1">当status为1时,显示该行</p> </div> <script src="../vue.min.js"></script> <script type="application/javascript"> var app = new Vue({ el: "#app", data: { status: 2 } }) </script> </body> </html>
5.2.3 v-show与v-if选择
v-if每次条件变化都会适当销毁或重建元素,若初始值为false,一开始不会渲染,只有第一次条件为真时才会编译。
v-show只是简单的css属性切换,无论条件真与否,都会编译。相比之下v-if适合条件不经常改变的场景,开销大。v-show适用于频繁切换。
5.3 列表渲染指令v-for
5.3.1 基本使用
将一个数组遍历或枚举一个对象循环显示。需结合in来使用。v-for与v-if一样同样可以用在内置标签<template>上。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>v-for基本使用</title> </head> <body> <div id="app"> <ul> <li v-for="book in books">{{ book.name }}</li> </ul> </div> <script src="../vue.min.js"></script> <script type="application/javascript"> var app = new Vue({ el: "#app", data: { books: [ {name: "《Vue.js实战》"}, {name: "《JavaScript语言精粹》"}, {name: "《JavaScript高级程序设计》"} ] } }) </script> </body> </html>
v-for支持一个可选参数作为当前项索引
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>v-for基本使用</title> </head> <body> <div id="app"> <ul> <li v-for="(book,index) in books">{{index}}-{{ book.name }}</li> </ul> </div> <script src="../vue.min.js"></script> <script type="application/javascript"> var app = new Vue({ el: "#app", data: { books: [ {name: "《Vue.js实战》"}, {name: "《JavaScript语言精粹》"}, {name: "《JavaScript高级程序设计》"} ] } }) </script> </body> </html>
遍历对象属性,默认是对象value
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>5.3.1 v-for遍历对象属性</title> </head> <body> <div id="app"> <span v-for="value in user">{{value}}</span> </div> <script src="../vue.min.js"></script> <script type="application/javascript"> var app = new Vue({ el: "#app", data: { user: { name: "Aresn", gender: "女", age: 38 } } }) </script> </body> </html>
v-for遍历对象属性时,可以添加key和index可选参数
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>5.3.1 v-for遍历对象属性</title> </head> <body> <div id="app"> <ul> <li v-for="(value,key,index) in user">{{index}}-{{key}}:{{value}}</li> </ul> </div> <script src="../vue.min.js"></script> <script type="application/javascript"> var app = new Vue({ el: "#app", data: { user: { name: "Aresn", gender: "女", age: 38 } } }) </script> </body> </html>
v-for迭代整数
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>5.3.1 v-for迭代整数</title> </head> <body> <div id="app"> <span v-for="n in 10">{{n}}</span> </div> <script src="../vue.min.js"></script> <script type="application/javascript"> var app=new Vue({ el:"#app" }) </script> </body> </html>
5.3.2 数组更新
Vue的核心就是数据与视图的双向绑定,当修改数组时,Vue会检测到数据变化,使用v-for渲染的视图也会例及更新。当通过索引直接设置项或修改数组长度,Vue是无法检测到的。
Vue包含了观察数据变化的方法,使用它们可改变数组也会触发视图更新;
如下7个方法会改变调用的原始数组:
- push(),在数据后面添加一项
- pop()
- shift()
- unshift()
- splice()
- sort()
- reverse()
如下三个方法不会改变原始数组,它们返回一个新的数组,当然可以用新数组来替换原数组。
- filter()
- concat()
- slice()
5.3.3 排序与过滤
当不想改变原数组,想通过一个数组副本来做过滤或排序显示时,可以使用计算属性来返回过滤或排序后的数组
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>5.3.3 过滤与排序</title> </head> <body> <div id="app"> <ul> <template v-for="book in filterBooks"> <li>书名:{{book.name}}}</li> <li>作者:{{book.author}}}</li> </template> </ul> </div> <script src="../vue.min.js"></script> <script type="application/javascript"> var app =new Vue({ el:"#app", data:{ books:[ { name:"书籍1", author:"作者1" }, { name:"书籍2", author:"作者2" }, { name:"书籍3", author:"作者3" } ] }, computed:{ filterBooks:function(){ return this.books.filter(function (book) { return book.name.match("2"); }) } } }) </script> </body> </html>
增加排序计算
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>5.3.3 过滤与排序</title> </head> <body> <div id="app"> <ul> <template v-for="book in filterBooks"> <li>书名:{{book.name}}}</li> <li>作者:{{book.author}}}</li> </template> </ul> </div> <script src="../vue.min.js"></script> <script type="application/javascript"> var app =new Vue({ el:"#app", data:{ books:[ { name:"书籍1", author:"作者1" }, { name:"书籍2", author:"作者2" }, { name:"书籍3", author:"作者3" } ] }, computed:{ filterBooks:function(){ return this.books.filter(function (book) { return book.name.match("2"); }) }, sortedBooks:function () { return this.books.sort(function (a, b) { return a.name.length < b.name.length; }) } } }) </script> </body> </html>
5.4 方法与事件
5.4.1 基本用法
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>5.4.1基本使用</title> </head> <body> <div id="app"> 点击次数:{{counter}} <button @click="handleAdd()">+1</button> <button @click="handleAdd(10)">+10</button> </div> <script src="../vue.min.js"></script> <script type="application/javascript"> var app=new Vue({ el:"#app", data:{ counter:0 }, methods:{ handleAdd:function (count) { count = count || 1; this.counter+=count; } } }) </script> </body> </html>
Vue提供了一个特殊变了$event,用于访问原生DOM事件,如阻止连接打开。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>5.4.1基本使用</title> </head> <body> <div id="app"> 点击次数:{{counter}} <button @click="handleAdd()">+1</button> <button @click="handleAdd(10)">+10</button> <!--Vue提供的特殊变量$event,用于访问原生DOM事件--> <a href="https://www.123.com" @click="handleClick('禁止打开',$event)">连接</a> </div> <script src="../vue.min.js"></script> <script type="application/javascript"> var app=new Vue({ el:"#app", data:{ counter:0 }, methods:{ handleAdd:function (count) { count = count || 1; this.counter+=count; }, handleClick:function (message, event) { event.preventDefault();//阻止默认动作 window.alert(message); } } }) </script> </body> </html>
5.4.2 修饰符
在上例使用的event.preventDefault()也可以使用Vue事件的修饰符来实现。在@绑定事件后加小圆点"."再跟一个后缀。修饰符可以连续调用。
- .stop:停止事件冒泡
- .prevent:阻止默认动作
- .capture
- .self:事件在元素本身
- .once:只触发一次
键盘修饰符,只有当按某个键时调用该方法,@keyCode.n="func"
5.5 实战:利用计算属性、指令等知识开发购物车
列表的splice方法:splice(index,howmany,item1,.....,itemX)方法向/从数组中添加/删除项目,然后返回被删除的项目。
index:必需。整数,规定添加/删除项目的位置,使用负数可从数组结尾处规定位置。
howmany:必需。要删除的项目数量。如果设置为 0,则不会删除项目。
item1, ..., itemX:可选。向数组添加的新项目。
index.html
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
<!DOCTYPE html> <html lang="en" xmlns:v-on="http://www.w3.org/1999/xhtml" xmlns:v-bind="http://www.w3.org/1999/xhtml"> <head> <meta charset="UTF-8"> <title>购物车示例</title> <link rel="stylesheet" href="style.css"> </head> <body> <div id="app" v-cloak> <template v-if="list.length"> <table> <thead> <tr> <ht></ht> <ht>商品名称</ht> <ht>商品单价</ht> <ht>购买数量</ht> <ht>操作</ht> </tr> </thead> <tbody> <tr v-for="(item,index) in list"> <td>{{index+1}}</td> <td>{{item.name}}</td> <td>{{item.price}}</td> <td> <button v-on:click="handleReduce(index)" v-bind:disabled="item.count === 1">- </button> {{item.count}} <button v-on:click="handleAdd(index)">+</button> </td> <td> <button v-on:click="handleRemove(index)">移除</button> </td> </tr> </tbody> </table> <div>总价:¥{{totalPrice}}</div> </template> <div v-else>购物车为空</div> </div> <script src="vue.min.js"></script> <script src="index.js"></script> </body> </html>
index.js
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
var app = new Vue({ el: "#app", data: { list: [ {id: 1, name: "iphone 7", price: 6188, count: 1}, {id: 2, name: "iPad Pro", price: 5888, count: 1}, {id: 3, name: "MacBook Pro", price: 21888, count: 1}, ] }, computed: { totalPrice: function () { var total = 0; for (var i = 0; i < this.list.length; i++) { var item = this.list[i]; total += item.price * item.count; } return total.toString().replace(/\B(?=(\d{3})+$)/g, ','); } }, methods: { handleReduce: function (index) { //这里再次判断,避免事件绑定在非button元素上,如div,span等,非button元素disabled特性不生效 if (this.list[index].count === 1) return; this.list[index].count--; }, handleAdd: function (index) { this.list[index].count++; }, handleRemove: function (index) { this.list.splice(index, 1) }, } })
index.css
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
[v-cloak]{
display: none;
}
table{
border: 1px solid #e9e9e9;
border-collapse: collapse;
border-spacing: 0;
empty-cells: show;
}
th,td{
padding: 8px 16px;
border: 1px solid #e9e9e9;
text-align: left;
}
th{
background: #f7f7f7;
color: #5c6b77;
font-weight: 600;
white-space: nowrap;
}