简单的了解一哈 Vue3和Vue2的响应式原理🪶?【vue3:proxy | vue2:Object.defineProperty()】🎈🎈🎈
vue的新项目开发者经常遇到响应式问题,那么vue2和vue3的响应式原理实现流程和主要的区别是 如何~~~ vue3 ——— proxy ♦️ vue2 ———— Object.defineProperty() ?
1. vue2.x的响应式原理
实现原理:通过Object.defineProperty()对属性的读取,修改进行拦截。(也叫数据劫持)即对数据的操作进行监听
let data = {
name: "张三",
age: 30
}
let p = {}
Object.defineProperty(p, 'name', {
get() {
console.log('访问了name属性');
return data.name
},
set(val) {
console.log('设置name属性');
data.name = val
}
})
//如上存在2个问题:
// 无法添加和删除属性
// 无法捕获到修改数组下标改变对应数组
如上存在2个问题:
无法添加和删除属性
无法捕获到修改数组下标改变对应数组
1.1 vue2.x存在的问题
-
对象数据新增属性和删除属性,界面不会响应更新~~看看下面的列子:
<template>
<div id="app">
<p>{{ person.name }}</p>
<p>{{ person.age }}</p>
<p v-if="person.sex">{{ person.sex }}</p>
<button @click="addSex">添加属性</button>
<button @click="deleteAge">删除属性</button>
</div>
</template>
<script>
import Vue from "vue";
export default {
name: "App",
data() {
return {
person: {
name: "张三",
age: 20,
},
};
},
components: {},
methods: {
addSex() {
// this.person.sex = "男";
// console.log(this.person); // 数据被修改,但是vue监测不到
// this.$set(this.person, "sex", "男"); // 修改为第一种方式,vue可以检测到
Vue.set(this.person, "sex", "男"); // 修改为第二种方式,vue也可以检测到
console.log(this.person);
},
deleteAge() {
// delete this.person.age; // age被删除改,但是vue监测不到
this.$delete(this.person, "age"); // 修改为第一种方式,vue可以检测到
Vue.delete(this.person, "age"); // 修改为第二种方式,vue可以检测到
console.log(this.person);
},
},
};
</script>
addSex():
this.person.sex = "男";
console.log(this.person); // 数据被修改,但是vue监测不
this.$set(this.person, "sex", "男"); // 修改为第一种方式,vue可以检测到
Vue.set(this.person, "sex", "男"); // 修改为第二种方式,vue也可以检测到
console.log(this.person);deleteAge()
delete this.person.age; // age被删除改,但是vue监测不到
this.$delete(this.person, "age"); // 修改为第一种方式,vue可以检测到
Vue.delete(this.person, "age"); // 修改为第二种方式,vue可以检测到
console.log(this.person);
数组数据直接通过修改下标,界面不会响应更新
<div id="app">
<p v-for="(item, index) in nameArr" :key="index">{{ item }}</p>
<button @click="update">添加属性</button>
</div>
<script>
import Vue from "vue";
export default {
name: "App",
data() {
return {
nameArr: ["刘备", "关羽"],
};
},
methods: {
update() {
// this.nameArr[0] = "张飞"; // 数据被修改了,但是vue 检测不到
// this.nameArr.splice(0, 1, "张飞"); // 修改为第一种方式,数据可以被检测到
// this.$set(this.nameArr, 0, "张飞"); // 修改为第二种方式,数据可以被检测到
Vue.set(this.nameArr, 0, "张飞"); // 修改为第三种方式,数据可以被检测到
console.log(this.nameArr);
},
},
};
</script>
update()
this.nameArr[0] = "张飞"; // 数据被修改了,但是vue 检测不到
this.nameArr.splice(0, 1, "张飞"); // 修改为第一种方式,数据可以被检测到
this.$set(this.nameArr, 0, "张飞"); // 修改为第二种方式,数据可以被检测到
Vue.set(this.nameArr, 0, "张飞"); // 修改为第三种方式,数据可以被检测到
console.log(this.nameArr);
2、vue3响应式原理
首先看一下vue3是否还存在vue2.x 中的问题: ~~~对象数据新增属性和删除属性,不存在vue2.x 中的问题了。
<template>
<div>
<p>{{ person.name }}</p>
<p>{{ person.age }}</p>
<p>{{ person.sex }}</p>
<button @click="addSex">添加属性</button>
<button @click="deleteSex">删除属性</button>
</div>
</template>
<script>
import { reactive } from "vue";
export default {
name: "App",
components: {},
setup() {
let person = reactive({
name: "张三",
age: 20,
});
console.log(person);
//定义添加属性
function addSex() {
person.sex = "男";
console.log(person);
}
// 定义删除属性
function deleteSex() {
delete person.sex;
console.log(person);
}
return {
person,
addSex,
deleteSex,
};
},
};
</script>
数组数据直接通过修改下标,修改数组,不存在vue2.x 中的问题了💦💦💦
<template>
<div>
<p v-for="(item, index) in person.like" :key="index">{{ item }}</p>
<button @click="change">修改数组的值</button>
</div>
</template>
<script>
import { reactive } from "vue";
export default {
name: "App",
components: {},
setup() {
let person = reactive({
name: "张三",
age: 20,
like: ["打球", "敲代码"],
});
console.log(person); // proxy 实例对象
function change() {
person.like[0] = "打台球";
}
return {
person,
change,
};
},
};
</script>
- 数组数据直接通过修改下标,修改数组,不存在vue2.x 中的问题了💦💦💦
2.1 vue3响应式原理
首先说一下Reflect的作用。
// Reflect是window下的一个内置对象
// 1. 使用reflect 访问数据
let obj = {
name: '张三',
age: 20
}
console.log(Reflect.get(obj, 'name')); // 张三
// 2.使用Reflect 修改数据
Reflect.set(obj, 'age', 50)
console.log(obj);
//3.使用Reflect删除数据
Reflect.deleteProperty(obj, 'name')
console.log(obj);
vue3响应原理代码:
通过Proxy代理,拦截对象中任意属性的变化,包括属性的读取,修改、设置、删除。
通过Reflect 反射对被代理对象的属性进行操作。
let data = {
name: "张三",
age: 30
}
console.log(Proxy);
// 使用p 对象代理data, Proxy为window 下的内置代理函数
let p = new Proxy(data, {
// 读取属性
get(target, propName) {
// target 就是 data
console.log(`读取p上个${propName}属性`);
return Reflect.get(target, propName)
},
// 修改和设置属性
set(target, propName, value) {
// value 为赋的值
console.log(`修改p的${propName}属性`);
// target[propName] = value
Reflect.set(target, propName, value)
},
//删除属性
deleteProperty(target, propName) {
console.log(`删除p上的${propName}属性`);
// return delete target[propName]
return Reflect.deleteProperty(target, propName)
}
})
Vue3 的响应式系统通过 Proxy 实现了更强大、更高效的反应机制,解决了 Vue2 中的多个痛点,就是属性增删改查的时候页面监听不到数据的更新。对于现代浏览器项目,Vue3 的响应式系统是更优的选择