Vue渲染指令(三)

724 阅读5分钟

这是我参与8月更文挑战的第7天,活动详情查看:8月更文挑战

前言

今天是第三天啊,在此之前我们已经讲过了基本配置以及事件绑定,今天搞搞渲染指令。主要有条件渲染列表渲染更新检测

条件渲染

指令 v-if

概念: 允许使用 v-if / v-else / v-else-if 控制元素的渲染,这块内容只会在指令的表达式返回 truthy 值的时候被渲染。

语法:

  1. 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>
  1. 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>
  1. 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>

注意:

  1. v-if指令实现元素的隐藏是直接将该元素从DOM节点中删除,而v-show隐藏元素只是设置了元素的display: none;属性并没有把元素从DOM节点中移除。因为上面的特性在开发中需要频繁显示隐藏的元素请使用v-show,而只需显示一次的元素请使用v-if。(这也算是一道面试题哟~)
  1. 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>
  1. 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>

注意

需要注意有以下三点,也是重点!!!

  1. 当 Vue 正在更新使用 v-for 渲染的元素列表时,它默认使用“就地更新”的策略。如果数据项的顺序被改变,Vue 将不会移动 DOM 元素来匹配数据项的顺序,而是就地更新每个元素,并且确保它们在每个索引位置正确渲染。这个默认的模式是高效的,但是只适用于不依赖子组件状态或临时 DOM 状态(当前列表不会增加,删除,更新顺序)。解决方法,为每一个使用v-for遍历出来的DOM节点添加一个唯一key属性,以便它能跟踪每个节点的身份,从而重用和重新排序现有元素

  2. 建议尽可能在使用 v-for 时提供 key attribute,除非遍历输出的 DOM 内容非常简单,或者是刻意依赖默认行为以获取性能上的提升。key属性不需要做到全局唯一,只需要同一个循环遍历的兄弟元素之间不同就好了

  3. 数组排列或者删除的操作请谨慎使用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或者Vue.set方法修改数组指定下标的值用法:vm.set 或者Vue.set方法修改数组指定下标的值 用法: **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方法。就不会引起页面更新。

给对象添加新属性引起页面更新的方法 :

  1. 新对象替换旧对象
  2. 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内部的其他子属性对象

结尾

今天就先到这里啦!我们下期再见!码字不易,觉得不错的可以动动小指头点点赞啥的哟~

系列文章

Vue系列

Vue-Router系列

Vuex系列