条件渲染
v-show
- 等效于改变元素的
display
属性。就是说,不论是否显示,浏览器都会渲染。适用于切换频率高的场合 v-show
不支持<template>
元素
<div id="app">
<p v-show="show">v-show 的使用</p>
<!-- 属性值可以是表达式,但返回的必须是布尔值 -->
<p v-show="2 == 2">v-show 的使用</p>
</div>
let vm = new Vue({
el: "#app",
data: {
show: true
}
});
v-if
- 不显示的话,浏览器则不渲染。适用于切换频率低的场合
<p v-if='vIf'>通过</p>
<p v-else>不通过</p>
let vm = new Vue({
el: "#app",
data: {
vIf: true
}
});
当然,属性值也可以是表达式:
<p v-if="score >= 90">优秀</p>
<p v-else-if="score >= 80 && score < 90">良好</p>
<p v-else-if="score >= 60 && score < 80">及格</p>
<p v-else>不及格</p>
let app = new Vue({
el: "#app",
data: {
score: 100
},
});
注意:v-if
、v-else-if
、v-else
必须顺序使用,中间不可插入其他标签!、
v-if
vs v-show
v-if
是“真正”的条件渲染,在切换过程中,条件块内的事件监听器和子组件会适当地被销毁和重建v-if
也是惰性的:需要显示时,才会渲染条件块;一直不显示,则一直不渲染- 相比之下,
v-show
就简单得多 —— 不管是否需要显示,元素总是会被渲染,并且只是简单地基于 CSS 进行切换 - 一般来说,
v-if
有更高的切换开销,而v-show
有更高的初始渲染开销
因此,如果需要非常频繁地切换,则使用v-show
较好;如果在运行时条件很少改变,则使用v-if
较好
key
值
Vue 会尽可能地复用已有元素,而不是从头开始渲染
<button @click="change">切换 loginType</button>
<template v-if="loginType == true">
<label>Username</label>
<input placeholder="Enter your username">
</template>
<template v-else>
<label>Email</label>
<input placeholder="Enter your email address">
</template>
let vm = new Vue({
el: "#app",
data: {
loginType: true
},
methods: {
change() {
this.loginType = !this.loginType;
}
}
});
上例中,切换 loginType
将不会清除用户已经输入的内容。因为两个模板使用了相同的元素,<input>
不会被替换掉 —— 仅仅是替换了它的 placeholder
如果我们想阻止复用,重头渲染,我们可以给需要的标签设置 key
属性,属性值为唯一标识
<template v-if="loginType == true">
<label>Username</label>
<input placeholder="Enter your username" key="username-input">
</template>
<template v-else>
<label>Email</label>
<input placeholder="Enter your email address" key="email-input">
</template>
现在,每次切换时,输入框都将被重新渲染。
注意,<label>
元素仍会被高效地复用,因为它们没有设置 key
属性
列表渲染
数据的显示
- 遍历对象:
v-for = (item, name, index) in/of 对象
<ul>
<li v-for="(item, name, index) of obj">
<p>{{item}} - {{name}} - {{index}}</p>
</li>
</ul>
- 遍历数组:
v-for = (item, index) in/of 数组
<li v-for="(item, index) of arr">
<p>{{item}} - {{index}}</p>
</li>
- 遍历字符串
<li v-for="(item, index) of str">
<p>{{item}} - {{name}}</p>
</li>
- 遍历到指定数字
<li v-for="(item, index) of 10">
<p>{{item}} - {{index}}</p>
</li>
- 当
v-if
与v-for
一起使用时,v-for
的优先级比v-if
高 (先执行),所以v-if
里面可以获取到v-for
的数据item
- 但是,永远不要把
v-if
和v-for
同时用在同一个元素上(极不推荐)
我们可以将通过计算属性 computed 过滤数据,在模版上使用过滤后的数据
<ul>
<li v-for="item of arr2">
<p>姓名:{{item.name}}、年龄:{{item.age}}</p>
</li>
</ul>
let vm = new Vue({
el: "#app",
data: {
arr1: [{
name: "superman",
age: 22
}, {
name: "superwoman",
age: 21
}, {
name: "superSon",
age: 17
}]
},
computed: {
arr2() {
let arr2 = this.arr1.filter((item) => {
return item.age > 18
})
return arr2
}
}
});
我们也可以配合 template 标签使用:
<ul>
<template v-for="item of arr1">
<li v-if="item.age >= 18">
<p>姓名:{{item.name}}、年龄:{{item.age}}</p>
</li>
</template>
</ul>
数据的代理
- 对于数组数据,Vue2 代理的是数组本身,就是说,通过
this.arr[index]
修改、添加数组的元素,数据会被修改,但页面不会改变
<button @click="add"> 添加数组元素 </button>
<button @click="change"> 修改数组元素 </button>
<span v-for="item in arr"> {{item}} </span>
let vm = new Vue({
el: "#app",
data: {
arr: ["s", "p", "m"]
},
methods: {
add() { // 添加数组元素
console.log("原数组数据", this.arr);
this.arr[this.arr.length] = "!";
console.log("新数组数据", this.arr);
},
change() { // 修改数组元素
console.log("原数组数据", this.arr);
this.arr[2] = "w";
console.log("新数组数据", this.arr);
}
}
});
- 变更方法
可以改变原数组的方法:push()
、pop()
、shift()
、unshift()
、splice()
、sort()
、reverse()
<button @click="add"> 添加数组元素 </button>
<button @click="change"> 修改数组元素 </button>
<span v-for="item in arr"> {{item}} </span>
let vm = new Vue({
el: "#app",
data: {
arr: ["s", "p", "m"]
},
methods: {
add() {
console.log("原数组数据", this.arr);
this.arr.push("!");
console.log("新数组数据", this.arr);
},
change() {
console.log("原数组数据", this.arr);
this.arr.splice(2, 1, "w");
console.log("新数组数据", this.arr);
}
}
});
- 替换数组
也可以通过 filter
、map
等函数,对原数组变量进行重新赋值
<button @click="reduce"> 过滤数组元素 </button>
<span v-for="item in arr"> {{item}} </span>
let vm = new Vue({
el: "#app",
data: {
arr: ["s", "p", "m"]
},
methods: {
reduce() {
console.log("原数组数据", this.arr);
this.arr = this.arr.filter(item => item == "s");
console.log("新数组数据", this.arr);
}
}
});
你可能认为这将重新渲染整个列表。事实并非如此。Vue 为了使得 DOM 元素得到最大范围的重用而实现了一些智能的启发式方法,所以用一个含有相同元素的数组去替换原来的数组是非常高效的操作
- 对于对象数据,Vue2 代理的也是整个对象,就是说,如果只通过
obj.attr = value
来改变对象数据的某个属性值 / 为对象数据添加新属性,数据会被改变,但页面不会重新渲染,即显示的数据不会变
<button @click="add"> 添加新属性 </button>
<button @click="change"> 修改属性值 </button>
<span v-for="item in obj"> {{item}} </span>
let vm = new Vue({
el: "#app",
data: {
obj: {
name: "superman",
age: 22
}
},
methods: {
add() {
console.log("原对象数据", this.obj);
this.obj.sex = "male";
console.log("新对象数据", this.obj);
},
change() {
console.log("原对象数据", this.obj);
this.obj.age = 23;
console.log("新对象数据", this.obj);
}
}
});
- 替换对象
所以,我们也需要通过改变原对象,才能改变页面上显示的数据
<button @click="change"> 修改整个对象 </button>
<span v-for="item in obj"> {{item}} </span>
let vm = new Vue({
el: "#app",
data: {
obj: {
name: "superman",
age: 22
}
},
methods: {
change() {
console.log("原对象数据", this.obj);
let newObj = {}; // 创建新对象
for (let [key, value] of Object.entries(this.obj)) { // 使用解构赋值
newObj[key] = value; // 复制原对象的属性
};
newObj.sex = "male"; // 添加属性 / 修改属性值
this.obj = newObj; // 对原对象重新赋值
console.log("新对象数据", this.obj);
}
}
});
- 调用 set 方法
也可以使用 set(对象, 属性名, 属性值)
来添加属性 / 修改属性值
语法:Vue.set(对象, 属性名, 属性值)
/ Vue实例.$set(对象, 属性名, 属性值)
<p v-for="(item, name, index) of obj">{{item}} - {{name}} - {{index}}</p>
<button @click="change">点击</button>
let vm = new Vue({
el: "#app",
data: {
obj: {
name: "superman",
age: 21,
}
},
methods: {
change() {
Vue.set(this.obj, "age", "22"); // 修改属性值
this.$set(this.obj, "sex", "male"); // 添加属性
}
}
});
绑定 key
属性
- 如果不设置
key
属性, 修改 DOM 时,会尽可能的复用已有的 DOM。就是说,如果 DOM 一样的话,Vue 会照搬原来的 DOM,不会创建新的 DOM - 设置
key
属性时, Vue 会基于key
的变化重新排列元素顺序, 且会移除key
不存在的元素。就是说,如果虚拟 DOM 之间的key
属性值不一样,Vue 会创建新的真实 DOM - 有相同父元素的子元素,必须有独特的
key
值,重复的key
值会造成渲染错误
<button @click="add">点击添加新数据项</button>
<ul>
<!-- 此处使用元素的唯一标识作为 key 的属性值 -->
<li v-for="(item, index) in arr" :key="item.id">
<span>姓名: {{item.name}}、 index: {{index}}、 id: {{item.id}}</span> <input type="text">
</li>
</ul>
let vm = new Vue({
el: "#app",
data: {
arr: [{
id: 1,
name: "谢老师",
}, {
id: 2,
name: "黄大力",
}, {
id: 3,
name: "朱古力",
}]
},
methods: {
add() { // 在数组头部添加新元素
this.arr.unshift({
id: 4,
name: "美少女"
});
}
}
});
如果不设置 key 属性,则默认为 :key="index"
。此时,会在一些改变 DOM 顺序的操作 (eg:逆序添加、逆序删除) 上,出现渲染错误
<button @click="add">点击添加新数据项</button>
<ul>
<!-- 此处没有使用元素的唯一标识作为 key 的属性值,对于会改变 DOM 顺序的操作上,会出现渲染错误 -->
<li v-for="(item, index) in arr" :key="index">
<span>姓名: {{item.name}}、 index: {{index}}、 id: {{item.id}}</span> <input type="text">
</li>
</ul>
所以,如果后期需要对数据项进行操作的话,最好设置 key
值为数据项的唯一标识!!!