使用Object.defineProperties()模拟实现Vue的绑定原理
版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/weixin_43348064/article/details/106178002
Vue的绑定原理
Vue的绑定原理可以概括为:保护Data属性+观察这模式+新Dom树(虚拟)Vue的绑定原理可以参看Vue的绑定原理
我们以下面的代码为例
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Document</title>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
</head>
<body>
<div id="app">
<h5>Vue</h5>
<p>计数:<span>{{count}}</span></p>
<h5>hello word</h5>
<p>计次:<span>{{num}}</span></p>
<p>计数:<span>{{count}}</span></p>
</div>
<script>
var data = {
count: 1,
num: 0,
};
new Vue({
el: "#app",
data: data,
});
</script>
</body>
</html>
效果图

代码执行流程
上面是代码的执行流程,和Vue的绑定原理图。我们就可以根据上面的图使用Object.definedProperties()模拟Vue的绑定原理。
Object.defineProperties()模拟实现Vue的绑定原理
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Document</title>
</head>
<body>
<div id="app">
<h5>Vue</h5>
<p>计数:<span>{{count}}</span></p>
<h5>hello word</h5>
<p>计次:<span>{{num}}</span></p>
<p>计数:<span>{{count}}</span></p>
</div>
<script>
var data = {
num: "zhengwenda",
count: 1,
};
//一、改造data对象的属性,并保护data中的每个属性
// 1. 使用Object.keys来遍历data的属性名;
var keys = Object.keys(data);
console.log(keys);
//Vue的绑定原理,保护data属性,并创建get,set方法
//这里因为不确定data里面有多少个属性,所以这里使用for of 循环遍历data的属性
for (var key of keys) {
//这里使用匿名函数自调,如果不使用匿名函数自调,获得的key就不是当前需要的key,而是遍历当最后一个属性
//所以这里需要使用匿名函数自调
//key是局部变量
//每遍历data中的一个变量,就要改造这个变量
(function (key) {
console.log(key);
Object.defineProperties(data, {
//保护当前的变量,定义一个"_key"变量来保护原变量
//在定义对象时,属性名禁止使用模板字符串 所以不能用`_${key}`定义属性名
//在定义对象时,属性名禁止使用拼接字符串 所以不能用“_”+{key}定义属性名
//ES6语法新语法,专门用于动态生成属性名,这里只能使用[拼接字符串或模板字符串]的方式定义属性名
[`_` + key]: {
value: data[key],
writable: true,
enumerable: false, //半隐藏
},
//用一个和当前属性同名的访问器属性,替代data中的原普通属性
[key]: {
get() {
return this[`_${key}`];
},
set(value) {
this[`_${key}`] = value;
console.log(`${key}发生了变化`);
change(key);
},
enumerable: true,
},
});
})(key);
}
//密封 每个属性的configurable:false;
Object.seal(data);
console.log(data);
setInterval(function () {
data.count += 1;
}, 1000);
//二、创建虚拟Dom树
//先定义个数组,存放虚拟Dom树
var arr = [];
//定义一个函数,来扫描真实Do树
function getChildren(parent) {
var children = parent.children;
//使用递归遍历出所有Dom树,
for (var c of children) {
if (c.children.length > 0) {
//递归调用,如果还有子节点
arguments.callee(c);
} else {
for (var key of keys) {
//判断内容是不是{{}}的如果是
if (c.innerHTML == `{{${key}}}`) {
//将c和c.innerHTML存入数组中,
arr.push({
elemt: c,
innerHTML: c.innerHTML,
});
//页面初次渲染时,将对应的属性值赋值给{{}}
c.innerHTML = data[key];
}
}
}
}
}
//传入根节点
getChildren(document.getElementById("app"));
console.log(arr);
//如果set发生变化时,会通知给观察者进行修改,这个change相当于观察者
function change(key) {
//遍历虚拟Dom树,将新值赋值给对应的{{}}
for (var obj of arr) {
if (obj.innerHTML == `{{${key}}}`) {
obj.elemt.innerHTML = data[key];
}
}
}
</script>
</body>
</html>
效果图
控制台输出


这样就基本实现出Vue的绑定原理,使用Object.defineProperties()模拟实现出Vue的绑定原理
评论
匿名评论
隐私政策
你无需删除空行,直接评论以获取最佳展示效果