vue2响应式原理
通过Object.defineProperty()
对属性的读取,修改进行数据劫持;
get捕获 获取的数据;set捕获 修改的数据;但是添加和删除属性是捕获不到的;
1 2 3 4 5
| Object.defineProperties(p,"name",{ get(){}, set(){} })
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
| let person={ name:"张三", age:20 };
let p = {};
Object.defineProperty(p,"name",{ get(){ return person.name; }, set(value){ console.log("有人修了了name属性"); person.name=value; } });
Object.defineProperty(p,"age",{ get(){ return person.age; }, set(value){ console.log("有人修了了age属性"); person.age=value; } })
|
添加
和删除
捕获不到;
vue2响应式出现的问题及解决方法
对象中,新增属性、删除属性、界面不会更新(数据会变);
问题复现
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40
| <template> <div> <h2>{{ person.name }}</h2> <h2 v-show="person.age">{{ person.age }}</h2> <h2 v-show="person.sex">{{ person.sex }}</h2>
<button @click="addSex">添加一个属性</button> <button @click="delName">删除一个属性</button> </div> </template>
<script> export default { data() { return { person: { name: "张三", age: 18, }, }; }, methods: { addSex() { console.log(this.person.sex); this.person.sex = "女"; console.log(this.person.sex); }, delName() { console.log(this.person.age); delete this.person.age; console.log(this.person.age); }, }, }; </script>
<style> </style>
|
点击添加属性的按钮;点击删除对象的按钮;
person对象中有值了,但是页面不渲染
解决方法:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
| import Vue from "vue"; export default { data() { return { person: { name: "张三", age: 18, }, }; }, methods: { addSex() { Vue.set(this.person,"sex","女"); }, delName() { Vue.delete(this.person,"age"); }, }, };
|
直接通过下标修改数组,界面不会自动更新
问题复现
点击之后数组变了,页面不渲染
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33
| <template> <div> <h2>{{ person.hobby }}</h2> <button @click="changeLove">修改第一个爱好</button> </div> </template>
<script>
import Vue from "vue"; export default { data() { return { person: { name: "张三", age: 18, hobby:["学习","干饭"] }, }; }, methods: { changeLove(){ console.log(this.person.hobby); this.person.hobby[0]="study"; console.log(this.person.hobby); } }, }; </script>
<style> </style>
|
解决方法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| import Vue from "vue"; export default { data() { return { person: { name: "张三", age: 18, hobby:["学习","干饭"] }, }; }, methods: { changeLove(){ this.person.hobby.splice(0,1,"打游戏"); } }, };
|
vue3响应式原理
vue3响应式解决了vue2中响应式出现的问题;
通过Proxy(代理)对源对象变化的属性进行拦截,通过Reflect(反射)对源对象的属性进行操作;
知识点:
window.Proxy–>window内置的构造函数
1 2 3 4 5 6 7 8
| let person = { name: "张三", age: 20 };
const p = new Proxy(person,{});
|
重写一下 Proxy
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33
| let person = { name: "张三", age: 20 };
const p = new Proxy(person,{ get(target,propName){ console.log("某人读取了p上的属性",target,propName);
return target[propName]; }, set(target,propName,value){ console.log(`修改了p身上的${propName},我要去更新界面了`); target[propName]=value; }, deleteProperty(target,propName){ console.log(`删除了p身上的${propName},我要去更新界面了`); return delete target[propName]; } });
|
通过重写,发现 操作 都可以捕获到
但 vue3的底层 并不是通过 通过 获取到 target[propName] 这种来修改的;这种有缺陷,而是下面的Reflect;
知识点: 获取对象的某个属性,除了 obj.属性
之外还有下面这个新增的方法
window.Reflect() ;反射对象
Reflect.get(反射的对象,key);Reflect.set(反射的对象,key,value);Reflect.deleteProperty(反射的对象,key)
传统的 出现相同属性会出错,封装时需要大量的try,,,catch;Reflect 不会出错;
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35
| let obj = {a:1,b:2};
const x1 = Reflect.defineProperty(obj,'c',{ get(){ return 3; } })
const x2= Reflect.defineProperty(obj,'c',{ get(){ return 4; } })
if(x2){ console.log("某某操作成了") }else{ console.log("某某操作失败了"); }
|
将重写的代码稍加改动 (vue3响应式原理)
通过Proxy(代理)对源对象变化的属性进行拦截,通过Reflect(反射)对源对象的属性进行操作;
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36
| let person = { name: "张三", age: 20 };
const p = new Proxy(person,{ get(target,propName){ console.log("某人读取了p上的属性",target,propName);
return Reflect.get(target,propName); }, set(target,propName,value){ console.log(`修改了p身上的${propName},我要去更新界面了`); Reflect.set(target,propName,value); }, deleteProperty(target,propName){ console.log(`删除了p身上的${propName},我要去更新界面了`); return Reflect.deleteProperty(target,propName); } });
|