这是我参与8月更文挑战的第7天,活动详情查看:8月更文挑战
前言
今天是第三天啊,在此之前我们已经讲过了基本配置以及事件绑定,今天搞搞渲染指令。主要有条件渲染
,列表渲染
,更新检测
条件渲染
指令 v-if
概念: 允许使用 v-if / v-else / v-else-if 控制元素的渲染,这块内容只会在指令的表达式返回 truthy 值的时候被渲染。
语法:
- v-if="判别式"
<div id="app">
<div
:style="{width: '100px',height: '100px', backgroundColor: 'red'}"
v-if="show"
></div>
<button @click="show = !show">show/hidden</button>
</div>
<script>
new Vue({
el: '#app',
data: {
show: true
}
})
</script>
- v-if="判别式" v-else
<div id="app">
<div
:style="{width: '100px',height: '100px', backgroundColor: 'red'}"
v-if="show"
>白天</div>
<!-- v-if元素 与 v-else元素之间除了空行和注释以外不能有其他元素否则会报错 -->
<div :style="{width: '100px',height: '100px', backgroundColor: '#ccc'}" v-else>
晚上
</div>
<button @click="show = !show">show/hidden</button>
</div>
<script>
new Vue({
el: '#app',
data: {
show: true
}
})
</script>
- v-if="判别式" v-else-if="判别式" ... v-else
<div id="app">
<!-- 注意v-if v-else-if v-else元素之间除了空行和注释以外不能有其他任何节点 -->
<div v-if="score > 90">
优秀
</div>
<div v-else-if="score >= 85">
良好
</div>
<div v-else-if="score >= 60">
及格
</div>
<div v-else>
不及格
</div>
</div>
<script>
let vm = new Vue({
el: '#app',
data: {
score: 50
}
})
</script>
指令 v-show
概念: 允许使用 v-show 控制元素的显示隐藏
语法: v-show="判别式"
<div id="app">
<div v-show="show" style="width: 100px;height: 100px;background-color: red;">show</div>
<button @click="show = !show">show/hidden</button>
</div>
<script>
let vm = new Vue({
el: '#app',
data: {
show: true
}
})
</script>
注意:
- v-if指令实现元素的隐藏是直接将该元素从DOM节点中删除,而v-show隐藏元素只是设置了元素的display: none;属性并没有把元素从DOM节点中移除。因为上面的特性在开发中需要频繁显示隐藏的元素请使用v-show,而只需显示一次的元素请使用v-if。(这也算是一道面试题哟~)
- Vue 会尽可能高效地渲染元素,通常在使用v-if切换元素时, 会复用已有元素而不是从头开始渲染,下面的例子中元素切换并没有真的卸载掉上一个表单元素重新安装,而是复用了该元素只是修改其placeholder的属性值,在下面的的代码中切换 show 将不会清除用户已经输入到表单的内容
<div id="app">
<input v-if="show" placeholder="请输入密码">
<input v-else placeholder="请输入验证码">
<button @click="show = !show">show/hidden</button>
</div>
<script>
let vm = new Vue({
el: '#app',
data: {
show: true
}
})
</script>
- Vue提供了一个key属性来表示元素的独立性,简单来说key属性的值是一个字符串。只有在
兄弟元素(同一个if语句,同一个循环的同级元素)中key属性相同的元素才可以互相复用
。下面的代码中 两个兄弟表单元素因为key属性不同不能互相复用。所以在元素切换时上一个表单元素会被卸载,重新渲染新的表单元素
<div id="app">
<input key="1" v-if="show" placeholder="请输入密码">
<input key="2" v-else placeholder="请输入验证码">
<button @click="show = !show">show/hidden</button>
</div>
<script>
let vm = new Vue({
el: '#app',
data: {
show: true
}
})
</script>
列表渲染
指令 v-for
概念: Vue可以使用户v-for遍历数组或者对象循环渲染多个相同DOM节点,item
表示数组的每一项。index
表示项的下标
数组
v-for="item in arr"
<div id="app">
<ul>
<li v-for="item in arr" :key="item" :class="'item-'+item">{{item}}</li>
</ul>
</div>
<script>
new Vue({
el: '#app',
data: {
arr: ['a', 'b', 'c', 'd']
}
})
</script>
v-for="(item, index) in arr"
<div id="app">
<ul>
<li v-for="(item,index) in arr" :key="index" :class="'item-'+index">{{item}}</li>
</ul>
</div>
<script>
new Vue({
el: '#app',
data: {
arr: ['a', 'b', 'c', 'd']
}
})
</script>
对象
v-for="value in object"
<div id="app">
<ul>
<li v-for="val in obj" :key="val">{{val}}</li>
</ul>
</div>
<script>
new Vue({
el: '#app',
data: {
obj: {
name: '小明',
age: 19,
address: '深圳'
}
}
})
</script>
v-for="(value, key) in object"
<div id="app">
<ul>
<li v-for="(val,key) in obj" :key="key">{{key}}:{{val}}</li>
</ul>
</div>
<script>
new Vue({
el: '#app',
data: {
obj: {
name: '小明',
age: 19,
address: '深圳'
}
}
})
</script>
v-for="(value, key, index) in object"
<div id="app">
<ul>
// name : 小明 : 0
<li v-for="(val,key,index) in obj" :key="index" :class="'item-'+index">{{key}}:{{val}}:{{index}}</li>
</ul>
</div>
<script>
new Vue({
el: '#app',
data: {
obj: {
name: '小明',
age: 19,
address: '深圳'
}
}
})
</script>
注意
需要注意有以下三点,也是重点!!!
-
当 Vue 正在更新使用
v-for
渲染的元素列表时,它默认使用“就地更新”的策略。如果数据项的顺序被改变,Vue 将不会移动 DOM 元素来匹配数据项的顺序,而是就地更新每个元素,并且确保它们在每个索引位置正确渲染。这个默认的模式是高效的,但是只适用于不依赖子组件状态或临时 DOM 状态(当前列表不会增加,删除,更新顺序)。解决方法
,为每一个使用v-for遍历出来的DOM节点添加一个唯一key
属性,以便它能跟踪每个节点的身份,从而重用和重新排序现有元素 -
建议尽可能在使用
v-for
时提供key
attribute,除非遍历输出的 DOM 内容非常简单,或者是刻意依赖默认行为以获取性能上的提升。key属性不需要做到全局唯一,只需要同一个循环遍历的兄弟元素之间不同就好了 -
数组排列或者删除的操作
请谨慎
使用index作为key,index无论怎么删除下标永远都是从0 到 n,导致会删除掉错误dom节点
到了这里啊!有个特经典的案例Todo列表
,大家可以先看看todo是什么东西啊,这里给大家一个参考网址TodoMVC
,这里面有很多不同语言的案例,大家可以先看看,我们后面单独出一期Todo的完整案例。
更新检测
概念: Vue数据双向绑定的原理是在vue实例初始化时递归的给所有的对象属性绑定getter/setter方法,这样导致了两个问题。
问题一:数组的更新
数组的每一项不是对象,vue数据双向绑定不会递归的给数组的每一项绑定get/set,所以在vue中数组通过下标添加或者修改值的时候不会引起页面更新。
注意: Vue 数组中的 push(),pop(),shift(),unshift(),splice(),sort(),reverse()方法,都被进行了包裹二次封装(不是原生js方法),所以调用上面的方法将会触发视图更新
<div id="app">
<p v-for="(item,index) in arr" :key="index">{{item}}</p>
</div>
let vm = new Vue({
el: '#app',
data: {
arr: ['a','b','c','d']
}
})
vm.arr[1] = 'AAA' // 页面不会更新
vm.arr[4] = 'e' // 页面不会更新
可以引起数组更新视图的方法有三种:
- 方法一: 调用上面说的数组中的方法
- 方法二: 使用新数组替换旧数组
- 方法三: 使用vm.set**(数组,index,val) / Vue.set(数组,index,value)
let vm = new Vue({
el: '#app',
data: {
arr: ['a', 'b', 'c', 'd']
}
})
/*
vm.arr[1] = 'AAA' // 页面不会更新
vm.arr[4] = 'e' // 页面不会更新
*/
Vue.set(vm.arr, 1, 'CCCC') // 页面会更新
vm.$set(vm.arr, 4,'eee')// 页面会更新
问题二:对象的更新
因为在Vue初始化时对象中的所有属性都被添加了get/set,所以对象可以直接通过属性名修改就会引起页面的更细,但是如果在Vue实例化之后给某个对象添加新的属性,这个属性将不包含get/set方法。就不会引起页面更新。
给对象添加新属性引起页面更新的方法 :
- 新对象替换旧对象
- vm.$set / Vue.set 添加新属性,并给新属性绑定get set方法
用法: Vue.set(对象,'键名',属性值) vm.$set(对象,'键名',属性值)
<div id="app">
<p v-for="(val,key) in obj" :key="key">{{val}}</p>
</div>
<script>
let vm = new Vue({
el: '#app',
data: {
obj: {
name: '老李',
age: 18
}
}
})
vm.$set(vm.obj, 'address', '深圳') // 页面会更新
vm.$set(vm.obj, 'address', '广州') // 页面会更新
vm.obj.address = '佛山' //address 自动添加get set 页面会更新
Vue.set(vm.obj, 'hobby', '吃肉') // 页面会更新
</script>
注意: Vue.set/ vm.set不能直接修改
vm.$data
,只能修改$data内部的其他子属性对象
结尾
今天就先到这里啦!我们下期再见!码字不易,觉得不错的可以动动小指头点点赞啥的哟~