[TOC] >[success] ## 对象重新渲染 * 图解计划内属性 ~~~ 1.当vue被render 函数最后渲染后,会将data中的数据通过getter放到, watch中,当改变数据时候会通过setter重新渲染,因此计划内的数据指的就 是通过getter放到watch中的数据,wachter会触发接下来的vue的渲染,因此 就会有计划属性说法 ~~~ ![](https://box.kancloud.cn/7fb4e61f1ac46a9d8fc5a26d462c27f0_890x521.png) ~~~ 1.首先vue 中 只有计划好的数据,才能做相应渲染,什么样算是计划好的就是在 vue实例对象data中已经声明的举个例子: var vm = new Vue({ el: '#app', data: { msg:{} }, }); 根据上面的例子其中msg 是已经在计划内声明好的,但msg.title = '不在计划内 的',msg中的title就属于不在计划内,这样的数据不会被渲染,为了可以更好的理 解下面的案例将说明 ~~~ >[danger] ##### 不在在计划内的数据 ~~~ 1.刚才已经对不在计划内的数据做了解释,现在可以更进一步通过代码来讲解 2.下面案例中msg是计划内数据,但是msg.title不是计划内的,即使我们通过点击事件,给这个不在计划内的数据重新赋值,页面也不会重新渲染 ~~~ ![](https://img.kancloud.cn/2d/26/2d2665c2e337b0580efc3bd184709665_589x316.png) ~~~ html <!DOCTYPE html> <html lang="zh-cn"> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> <title></title> <style> </style> <script src="https://cdn.jsdelivr.net/npm/vue@2.5.11/dist/vue.js"></script> </head> <body> <div id="app"> <p @click='onChange'>1{{msg.title}}</p> </div> <script> var vm = new Vue({ el: '#app', data: { msg: {}, }, methods: { onChange() { this.msg.title = '我不在计划内' console.log(this.msg) }, }, }) </script> </body> </html> ~~~ >[danger] ##### 在计划中定义的数据 ~~~ 1.那上面的案例进行改造,msg.titl在计划内会发生什么变化 2.当我们点击p标签后发现数据在页面被重新渲染了 ~~~ ![](https://img.kancloud.cn/2b/b8/2bb8aedd2ce13c81f504cd56f7cd4e8f_653x379.png) ~~~html <!DOCTYPE html> <html lang="zh-cn"> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> <title></title> <style> </style> <script src="https://cdn.jsdelivr.net/npm/vue@2.5.11/dist/vue.js"></script> </head> <body> <div id="app"> <p @click='onChange'>1{{msg.title}}</p> </div> <script> var vm = new Vue({ el: '#app', data: { msg: { title: '' }, }, methods: { onChange() { this.msg.title = '我在计划内' console.log(this.msg) }, }, }) </script> </body> </html> ~~~ >[warning] ### 怎么保证不在计划内的值也被重新渲染 ~~~ 1.调用Vue的静态方法:set 2.调用实例上的方法 :$set 3.给计划内的对象重新赋值:vm.object = {key:'新的'} 4.添加指定属性重新构建赋值:Object.assign() ~~~ >[danger] ##### 第一种解决方法 -- set/$set ~~~ 1.Vue.set( target, key, value ),其中'target' 是 'Object | Array'对象或者是数 组,'key'是'string | number'字符串或者是数字,'value'是可以任意类型 2.vm.$set( target, key, value ),$set和set用法参数是一样,但要注意set是静态(类) 方法$set是实例方法,案例会有详细解说。 ~~~ * set ~~~ html <!DOCTYPE html> <html lang="zh-cn"> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> <title></title> <style> </style> <script src="https://cdn.jsdelivr.net/npm/vue@2.5.11/dist/vue.js"></script> </head> <body> <div id="app"> <p @click='onChange'>1{{msg.title}}</p> </div> <script> var vm = new Vue({ el: '#app', data: { msg: {}, }, methods: { onChange() { Vue.set(this.msg, 'title', '我不在计划内但我也能使用') }, }, }) </script> </body> </html> ~~~ * $set ($set 是实例方法因此也是this在内部直接调用) ~~~ html <!DOCTYPE html> <html lang="zh-cn"> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> <title></title> <style> </style> <script src="https://cdn.jsdelivr.net/npm/vue@2.5.11/dist/vue.js"></script> </head> <body> <div id="app"> <p @click='onChange'>1{{msg.title}}</p> </div> <script> var vm = new Vue({ el: '#app', data: { msg: {}, }, methods: { onChange() { // 我是 实例方法 this.$set(this.msg, 'title', '我不在计划内但我也能使用') }, }, }) </script> </body> </html> ~~~ >[danger] ##### 给计划内的对象重新赋值 ~~~ 1.第三个方法和第四个方法都是给对象重新赋值达到的效果,两者使用形式上不同 ~~~ * vm.object = {key:'新的'} ~~~html <!DOCTYPE html> <html lang="zh-cn"> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> <title></title> <style> </style> <script src="https://cdn.jsdelivr.net/npm/vue@2.5.11/dist/vue.js"></script> </head> <body> <div id="app"> <p @click='onChange'>1{{msg.title}}</p> </div> <script> var vm = new Vue({ el: '#app', data: { msg: {}, }, methods: { onChange() { this.msg = { 'title': '我简单粗暴把你这个msg这个计划对象直接换了' } }, }, }) </script> </body> </html> ~~~ * Object.assign({},this.object,{key,value}) ~~~ <!DOCTYPE html> <html lang="zh-cn"> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> <title></title> <style> </style> <script src="https://cdn.jsdelivr.net/npm/vue@2.5.11/dist/vue.js"></script> </head> <body> <div id="app"> <p @click='onChange'>1{{msg.title}}</p> </div> <script> var vm = new Vue({ el: '#app', data: { msg: {}, }, methods: { onChange() { this.msg = Object.assign({}, { title: '我用Object自带的方法也可以' }) }, }, }) </script> </body> </html> ~~~ >[info] ## 数组重新渲染 ~~~ 1.首先vue提供一套变异方法,会改变被这些方法调用的原始数组,使用这些方法 时候就不用去考虑数组会不会被渲染的问题 'push()' 'pop()' 'shift()' 'unshift()' 'splice()' 'sort()' 'reverse()' 2.但使用这些方法的时候就需要用新老数组替换的方式: filter(), concat() 和 slice() ,map()。 文档中对这种新老数组替换'是否会影响性能的解释': 你可能认为这将导致 Vue 丢弃现有 DOM 并重新渲染整个列表。幸运的是,事实并非如此。Vue 为了使得 DOM 元素得到最大范围的重用而实现了一些智能的启发式方法,所以用一个含有相同元素的数组去替换 原来的数组是非常高效的操作。 3.依旧支持set/$set 4.splice是个好方法会常用 ~~~ >[danger] ##### set/$set ~~~ 1.下面两个案例都为了解决vm.items[indexOfItem] = newValue不能被渲染的问题 ~~~ * set ~~~ 1.下面的案例会把我是重新渲染成替换 2.使用方法set 是Vue静态方法,通过Vue调用 3.使用Vue.set( array, indexOfItem, newValue) ~~~ ![](https://box.kancloud.cn/f051c3587ae1a8fb7173070f00a0762e_260x168.png) ~~~ <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> <!--导入Vue cdn 的网址--> <script src="https://cdn.jsdelivr.net/npm/vue@2.5.22/dist/vue.js"></script> </head> <body> <div id="app"> <p v-for="i in msg">{{i}}</p> <input v-model="pushArray"> <button @click="changeMsg">提交</button> </div> <script> // 创建 Vue 实例,得到 ViewModel var vm = new Vue({ el: '#app', data: { pushArray:'', msg:['我是', '测试', '数据'], }, methods:{ changeMsg(){ Vue.set(this.msg, 0, this.pushArray); } } }); </script> </body> </html> ~~~ * $set ~~~ 1.下面的案例会把我是重新渲染成替换 2.使用方法$set 是实例方法用this调用即可 3.使用this.$set( array, indexOfItem, newValue) ~~~ ~~~ <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> <!--导入Vue cdn 的网址--> <script src="https://cdn.jsdelivr.net/npm/vue@2.5.22/dist/vue.js"></script> </head> <body> <div id="app"> <p v-for="i in msg">{{i}}</p> <input v-model="pushArray"> <button @click="changeMsg">提交</button> </div> <script> // 创建 Vue 实例,得到 ViewModel var vm = new Vue({ el: '#app', data: { pushArray:'', msg:['我是', '测试', '数据'], }, methods:{ changeMsg(){ this.$set(this.msg, 0, this.pushArray); } } }); </script> </body> </html> ~~~ >[danger] ##### splice 是一个好方法 ~~~ 1.vm.items.splice(indexOfItem, 1, newValue),也能解决上述问题 ~~~ >[info] ## v-for 为什么要配合v-bind:key ~~~ 1.key:跟踪每个节点的身份,从而重用和重新排序现有元素 2.下面案例。如果没有使用key 就会造成checkbox 添加数据的时候勾选混乱,应 该遵循官方建议v-for 循环加上key ~~~ ~~~ <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> <script src="https://cdn.jsdelivr.net/npm/vue@2.5.22/dist/vue.js"></script> </head> <body> <div id="app"> <div> <label>Id: <input type="text" v-model="id"> </label> <label>Name: <input type="text" v-model="name"> </label> <input type="button" value="添加" @click="add"> </div> <!-- 注意: v-for 循环的时候,key 属性只能使用 number或者string --> <!-- 注意: key 在使用的时候,必须使用 v-bind 属性绑定的形式,指定 key 的值 --> <!-- 在组件中,使用v-for循环的时候,或者在一些特殊情况中,如果 v-for 有问题,必须 在使用 v-for 的同时,指定 唯一的 字符串/数字 类型 :key 值 --> <p v-for="item in list" :key="item.id"> <input type="checkbox">{{item.id}} --- {{item.name}} </p> </div> <script> // 创建 Vue 实例,得到 ViewModel var vm = new Vue({ el: '#app', data: { id: '', name: '', list: [ { id: 1, name: '李斯' }, { id: 2, name: '嬴政' }, { id: 3, name: '赵高' }, { id: 4, name: '韩非' }, { id: 5, name: '荀子' } ] }, methods: { add() { // 添加方法 this.list.unshift({ id: this.id, name: this.name }) } } }); </script> </body> </html> ~~~