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的根数据对象添加属性