vlambda博客
学习文章列表

vue监测数据的原理、vue.set的使用

我们更新列表中的某条数据,采用不同的方式更新,会出现不同的情况,如下面代码

<div id="app"> <button @click="updateInfo">更新张三数据</button> <ul> <li v-for="p in persons" ::key="p.id"> {{p.name}}--{{p.age}}--{{p.sex}} </li> </ul></div><script> Vue.config.productionTip = false; new Vue({ el: "#app", data: { persons: [ { id: 1, name: "张三", age: 21, sex: "男", }, { id: 2, name: "李四", age: 18, sex: "男", }, ], }, methods: { updateInfo() { /* 此种方式生效 this.persons[0].name = "王五"; this.persons[0].age = 22; this.persons[0].sex = "女"; */        this.persons.splice(0,1,{id:1,name:"王五",age:22,sex:"女"}) // 但这种不生效 this.persons[0] = { id: 1, name: "王五", age: 22, sex: "女" }; }, }, });</script>

为什么使用this.persons[0] = { id: 1, name: "王五", age: 22, sex: "女" };不生效

一、Vue是如何监测对象变化的

我们所传入的data,vue拿到之后进行加工,加工之后执行vm_data = data。为什么要进行加工?加工之后就可以实现响应式。当name修改之后,会执行调用setter,setter中的函数会使页面重新解析模板,模板重新解析生成新的虚拟DOM,然后进行新旧DOM对比,然后更新页面。

二、Vue监视数据的原理

1、vue会监视data中所有层次的数据。

2、如何监视对象中的数据?

通过setter实现监视,且要在new Vue时就传入要监测的数据。(简单说就是data中默认就声明了这些数据)

如果之前未声明,通过在对象中后追加的属性,Vue默认不做响应式处理。因为追加的属性没有getter和setter,比如:

<div id="app"> <p>姓名:{{student.name}}</p> <p>性别:{{student.sex}}</p> <p v-if="student.age">年龄:{{student.age}}</p> <button @click="addAge">添加年龄</button></div><script> const vm = new Vue({ el:"#app", data:{ student:{ name:"张三", sex:"男" } }, methods:{ addAge(){        this.student.age = 18;// 这种方式不生效 } } })</script>

上述代码我们执行之后查看数据发现,通过此方法追加的属性没有getter和setter

如果需要给后添加的属性做响应式,请使用如下API:

Vue.set(target,propertyName/index,value)或vm.$set(target,protertyName/index,value)

<div id="app"> <p>姓名:{{student.name}}</p> <p>性别:{{student.sex}}</p> <p v-if="student.age">年龄:{{student.age}}</p> <button @click="addAge">添加年龄</button></div><script> const vm = new Vue({ el:"#app", data:{ student:{ name:"张三", sex:"男" } }, methods:{ addAge(){        this.$set(this.student,"age",18) } } })</script>

上述代码我们执行之后查看数据发现,通过此方法新增的属性会被添加上getter和setter

3、如何监测数组中的数据?

通过包裹数组更新元素的方法实现,本质就是做了两件事:

  • 调用原生对应的方法对数组进行更新。

  • 重新解析模板,进而更新页面

在Vue修改数组中的某个元素一定要用如下方法:

  • 使用这些API:push()、pop()、shift()、unshift()、spice()、sort()、reverse()

    <div id="app"> <ul> <p>爱好:</p> <button @click="addHobby">增加一个爱好</button> <li v-for="(h,index) in hobby" :key="index">{{h}}</li> </ul></div><script> Vue.config.productionTip = false; var vm = new Vue({ el: "#app", data: { hobby: ["篮球", "羽毛球", "跑步"], }, methods: { addHobby() { this.hobby.push("跳舞");      }, }, });</script>
  • Vue.set()或vm.$set()

    <div id="app"> <ul> <p>爱好:</p> <button @click="addHobby">增加一个爱好</button> <li v-for="(h,index) in hobby" :key="index">{{h}}</li> </ul></div><script> Vue.config.productionTip = false; var vm = new Vue({ el: "#app", data: { hobby: ["篮球", "羽毛球", "跑步"], }, methods: {      addHobby() { this.$set(this.hobby, 3, "跳舞");      }, }, });</script>

特别注意:Vue.set()和vm.$set()不能给vm或vm的根数据对象添加属性