条件渲染
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;
}