vue-内置指令
条件渲染
v-if v-else-if v-else
vue在渲染元素时,出于效率考虑,会尽可能地复用已有的元素而非重新渲染
example:
html
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> <link rel="stylesheet" href="main.css"/> </head> <div id="app"> <template v-if="type === 'name'"> <label>用户名:</label> <input placeholder="输入用户名"> </template> <template v-else> <label>邮箱:</label> <input placeholder="输入邮箱"> </template> <button @click="handleToggleClick">切换输入类型</button> </div> <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script> <script src="main.js"></script> </body> </html>
js
var app = new Vue({ el: '#app', data: { type: 'name' }, methods: { handleToggleClick: function() { this.type = this.type === 'name' ? 'mail' : 'name'; } } });
输入内容后,点切换按钮,虽然dom变了,只是替换了placehoder,input元素被复用
如果不希望这样做,可以使用vue.js提供的key属性,让你自己决定是否复用元素,key的值必须是唯一的
v-show
v-show是改变元素的css属性display,当v-show表达式的值为false时,元素会隐藏
html
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> <link rel="stylesheet" href="main.css"/> </head> <div id="app"> <p v-show="status === 1">当status为1时显示该行</p> </div> <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script> <script src="main.js"></script> </body> </html>
js
var app = new Vue({ el: '#app', data: { status: 1 } });
列表渲染指令v-for
当需要将一个数组遍历或枚举一个对象循环显示时,就用到v-for,表达式需要结合in来实现
html
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> <link rel="stylesheet" href="main.css"/> </head> <div id="app"> <ul> <li v-for="book in books">{{ book.name }}</li> </ul> </div> <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script> <script src="main.js"></script> </body> </html>
js
var app = new Vue({ el: '#app', data: { books: [ { name:'python核心编程'}, { name:'go学习笔记'}, { name:'vue.js实战'} ] } });
在表达式中,books是数据,book是当前每个元素,元素.name能取出对应的值
v-for也能取出当前项的索引
<li v-for="(book,index) in books">{{index}}-{{ book.name }}</li>
v-for也能用在内置标签<template>上,将多个元素进行渲染
html
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> <link rel="stylesheet" href="main.css"/> </head> <div id="app"> <template v-for="book in books"> <ul> <li>书名:{{book.name}}</li> <li>作者:{{book.author}}</li> </ul> </template> </div> <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script> <script src="main.js"></script> </body> </html>
js
var app = new Vue({ el: '#app', data: { books: [ { name:'python核心编程', author:'a' }, { name:'go学习笔记', author: 'b' }, { name:'vue.js实战', author:'c' } ] } });
除数组外,对象的属性也是可以遍历的,两个可选参数,键值和索引
html
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> <link rel="stylesheet" href="main.css"/> </head> <div id="app"> <ul> <li v-for="(value,key,index) in user"> {{index}}-{{key}}:{{value}} </li> </ul> </div> <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script> <script src="main.js"></script> </body> </html>
js
var app = new Vue({ el: '#app', data: { user: { name:'somebody', age:28, gender:'男' } } });
数组更新
vue的核心是数据与视图的双向绑定,当修改数组时m,Vue会检测到数据变化,所以用v-for渲染的视图也会立即更新
push pop shift splice sort reverse
example:将之前一个示例的数据books添加一项
app.books.push({ name: 'css揭秘', author: 'd' });
使用以上方法会该改变被这些方法调用的原始数组,有些方法不会改变原数组
filter slice concat
example:找出书名包含vue的
app.books = app.books.filter(function (item) { return item.name.match(/vue/); });
vue在检测到数组变化时,并不是直接重新渲染整个列表,而是最大化复用dom,含有相同元素的项不会被重新渲染,因此新数组来替换旧数据
需要注意的是,以下变动的数组中,vue是不能检测到的,也不会触发视图更新
- 通过索引直接设置项
- 修改数组长度
解决第一个问题可以用vue内置的set方法
Vue.set(app.books,2,{ name: 'javascript', author: 'd', });
也可以用splice方法
app.books.splice(2,1,{ name: 'javascript', author: 'e' });
过滤与排序
如果不想改变原数组,想通过一个数组的副本来做过滤或排序的显示,可以用计算属性来返回过滤或排序后的数组
html
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> <link rel="stylesheet" href="main.css"/> </head> <div id="app"> <template v-for="book in filterBooks"> <ul> <li>书名:{{book.name}}</li> <li>作者:{{book.author}}</li> </ul> </template> </div> <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script> <script src="main.js"></script> </body> </html>
js
var app = new Vue({ el: '#app', data: { books: [ { name:'python核心编程', author:'a' }, { name:'go学习笔记', author: 'b' }, { name:'vue.js实战', author:'c' } ] }, computed: { filterBooks: function () { return this.books.filter(function (book) { return book.name.match(/vue/); }) } } });
排序和搜索类似,不会修改books
html
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> <link rel="stylesheet" href="main.css"/> </head> <div id="app"> <template v-for="book in sortedBooks"> <ul> <li>书名:{{book.name}}</li> <li>作者:{{book.author}}</li> </ul> </template> </div> <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script> <script src="main.js"></script> </body> </html>
js
var app = new Vue({ el: '#app', data: { books: [ { name:'python核心编程', author:'a' }, { name:'go语言学习笔记', author: 'b' }, { name:'vue.js实战', author:'c' } ] }, computed: { sortedBooks: function () { return this.books.sort(function (a,b) { return a.name.length < b.name.length }) } } });
方法与事件
example:监听一个按钮的点击事件,设置计数器,每次点击加1
html
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> <link rel="stylesheet" href="main.css"/> </head> <div id="app"> 点击次数:{{ counter }} <button @click="counter++">+1</button> </div> <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script> <script src="main.js"></script> </body> </html>
js
var app = new Vue({ el: '#app', data: { counter:0 } })
@click的表达式可以直接使用JavaScript语句,也可以是一个在Vue实例中methods选项内的函数名
example:再加一个加10的按钮
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> <link rel="stylesheet" href="main.css"/> </head> <div id="app"> 点击次数:{{ counter }} <button @click="handleAdd()">+1</button> <button @click="handleAdd(10)">+10</button> </div> <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script> <script src="main.js"></script> </body> </html>
js
var app = new Vue({ el: '#app', data: { counter:0 }, methods:{ handleAdd:function (count) { count = count || 1; this.counter += count } } })
练习:计算属性/指令开发购物车
html
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>购物车示例</title> <link rel="stylesheet" href="main.css"/> </head> <div id="app"> <template v-if="list.length"> <table> <thead> <tr> <th> <button @click="allChoose">全选</button> </th> <th></th> <th>商品名称</th> <th>商品单价</th> <th>商品数量</th> <th>操作</th> </tr> </thead> <tbody> <tr v-for="(item,index) in list"> <td> <input type="checkbox" v-model="item.checked"> </td> <td>{{ index+1 }}</td> <td>{{ item.name }}</td> <td>{{ item.price }}</td> <td> <button @click="handleReduce(index)" :disabled="item.count === 1">-</button> {{item.count}} <button @click="handleAdd(index)">+</button> </td> <td> <button @click="handleRemove(index)">移除</button> </td> </tr> </tbody> </table> <div>总价:{{totalPrice}}</div> </template> <div v-else>购物车为空</div> </div> <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script> <script src="main.js"></script> </body> </html>
js
var app = new Vue({ el:'#app', data: { list:[ { id:1, name:'iphone', price:6188, count:1, checked:true, }, { id:2, name:'ipad', price:5888, count:1, checked:true, }, { id:3, name:'mbp', price:18888, count :1, checked:true, } ] }, computed:{ totalPrice:function () { var total=0; for (var i=0;i< this.list.length;i++) { var item = this.list[i]; var status = this.list[i].checked; if (status === true) total += item.price * item.count; } return total.toString().replace(/\B(?=(\d{3})+$)/g,','); } }, methods:{ handleReduce: function (index) { 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) }, allChoose: function () { for (var i=0;i< this.list.length;i++) { this.list[i].checked = true; } } } });
css
table { border:1px solid #e9e9e9; } th,td { padding: 8px 16px; border: 1px solid #e9e9e9; text-align: left; }