前言
首先知道得知道什么叫数据响应式更新,那就是当我一个数据变动时,页面跟这个数据相关的也会随之变化。
如果用原生代码怎么实现页面更新
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>vue2的响应式更新原理</title>
</head>
<body>
<div class="lastName">
</div>
<div class="firstName">
</div>
<script src="index.js"></script>
</body>
</html>
const data = {
name: "周杰伦",
};
const getLastName = () => {
const dom = document.querySelector(".lastName");
if (dom) {
dom.innerHTML = "姓:" + data.name.substring(0, 1);
}
};
const getFirsttName = () => {
const dom = document.querySelector(".firstName");
if (dom) {
dom.innerHTML = "名:" + data.name.substring(1, data.name.length);
}
};
getLastName();
getFirsttName();
从上面的代码片段可以看出,当我们更改数据想要更新页面时要去调用使用到这个数据的函数,如果我们能够做到更新数据时,自动去调用这些依赖于这个数据的函数,那么我们就能够做到数据的响应式更新,而vue2则是用Object.defineProperty去实现数据响应式更新。
vue2中使用Object.defineProperty实现数据响应式更新的探讨
根据属性描述符的功能,我们可以知道当给一个属性赋值时,会触发属性描述符的set中的回调,而当用到i这个属性的时候会触发属性描述符的get中的回调,我们只要在get中收集依赖这个属性的函数,如何在set中自动调用这些方法,就可以做到数据响应式更新。
let nameVal = data.name;
Object.defineProperty(data, "name", {
get: function () {
//收集用到这个属性的函数
return nameVal;
},
set: function (val) {
//自动调用依赖于这个属性的函数
nameVal = val;
}
})
这里我们采用一个数组来存储这些函数,但是有可能存在一个函数中多次使用这个属性,也就是多次触发get,那么这个数组要做去重,然后在set中遍历数组,调用函数即可,代码如下:
let nameVal = data.name;
const funcArr = []
Object.defineProperty(data, "name", {
get: function () {
//收集用到这个属性的函数
if (!funcArr.includes(???)) {
funcArr.push(???)
}
return nameVal;
},
set: function (val) {
nameVal = val;
//自动调用依赖于这个属性的函数
for (let i = 0; i < funcArr.length; i++) {
funcArr[i]()
}
}
})
做到这一步,我们还是不知道到底这个funcArr应该push什么,那么怎么获得呢?其实我们初始化页面的时候,第一次去调这些方法的时候用应该全局变量把它存起来,再调函数,这时候函数会用到属性,触发get就可以拿到函数,调用完后再将全局变量等于null,代码如下
let nameVal = data.name;
const funcArr = [];
Object.defineProperty(data, "name", {
get: function () {
// 收集用到这个属性的函数
if (window.___func &&!funcArr.includes(window.___func)) {
funcArr.push(window.___func);
}
return nameVal;
},
set: function (val) {
nameVal = val;
// 自动调用依赖于这个属性的函数
for (let i = 0; i < funcArr.length; i++) {
funcArr[i]();
}
},
});
const runFunc = (fn) => {
window.___func = fn;
fn();
window.___func = null;
};
runFunc(getLastName);
runFunc(getFirsttName);
结尾
这样就实现了数据响应式更新,让我们来测试一下