Object.defineProperties()模拟实现Vue的绑定原理
咱们先写一个类似的html
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| <!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> </body>
</html>
|
然后实现一个类obsover的函数
一、改造data对象的属性,并保护data中的每个属性
使用Object.keys来遍历data的属性名;Vue的绑定原理,保护data属性,并创建get,set方法这里因为不确定data里面有多少个属性,所以这里使用for of 循环遍历data的属性
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 41 42 43 44 45 46
| <script> var data = { num: 2, count: 1, }; var keys = Object.keys(data); console.log(keys);
for (var key of keys) { (function (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); <script>
|
然后创建虚拟Dom树数组
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
| 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);
|
创造一个watcher
1 2 3 4 5 6 7 8
| function change(key) { //遍历虚拟Dom树,将新值赋值给对应的{{}} for (var obj of arr) { if (obj.innerHTML == `{{${key}}}`) { obj.elemt.innerHTML = data[key]; } } }
|
效果图
console