有这样一段HTML
<h1>Welcome</h1>
<h2>积分:{{scroe}}</h2>
<h1>用户名:{{uname}}</h1>
<h2>积分:{{score}}</h2>
分析new Vue()做了哪些事
1、改造data对象中的属性,并通过访问器属性对每个变量进行保护
var data = {
uname:"dingding",
score:2000
}
2、遍历真实DOM树,并创建虚拟DOM树->一个数组,记录可能会发生改变的元素
3、当元素发生改变时,通知虚拟DOM树,虚拟DOM树对比变化,将变化的值修改到真实DOM树上
模拟Vue绑定
var data = {
uname:"dingding",
score:2000
}
/ *
* 改造data为访问器属性
* /
//获取data里的全部属性名
var keys = Object.keys(data)
console.log(keys) //Array['uanme','score']
//遍历data中每个属性
for(var key of keys){
//闭包保护循环变量key
(function(key) {
//每遍历一个属性,就要改造这个属性为访问器属性
Object.defineProperties(data,{
//先定义一个以_开头,后面跟当前变量名的隐藏变量,实际保存当前属性值
[`_`+key]:{ //_uname
value:data[key], //data['uname']=>"dingding"
writable:true,
enumerable:false
},
//用一个和当前属性同名的访问器属性,代替data中原普通属性
[key]:{//uname
get(){return this[`_${key}}`]} //return this['_uname']
set(value){
this.[`_${key}`] = value // this['_uname']=value
//发出通知给虚拟DOM树
change(key)
}
enumerable: true
}
})
})(key)
}
/ *
* 构建虚拟DOM树
* /
//准备数组保存所有可能受影响的元素
var arr = []
// 创建虚拟DOM树
function getChildren(parent) {
//获取子节点
var children = parent.children
//遍历节点
for (var c of children) {
//如果子节点下边还有子节点,继续遍历
if (c.children.length>0) {
arguments.callee(c)
} else { // 如果是最后一级节点,则循环插入虚拟DOM树
//遍历data中每个变量名
for (var key of keys) {
//碰到{{}}包裹的变量,就添加进虚拟DOM树
if (c.innerHTML == `{{${key}}}`) {
arr.push({
elem:c, //虚拟DOM树中每个元素,不但要记录DOM元素对象地址[span,div...]
innerHTML:c.innerHTML //还要记录这个DOM元素哪个属性发生变化
})
//首次填充页面内容
c.innerHTML = data[key]
}
}
}
}
}
// 遍历body
getChildren(document.body)
/ *
* 通知函数
* /
function change(key) {
//遍历虚拟DOM树
for (var obj of arr) {
// 当当前节点的内容收到当前属性key变化影响时
if (obj.innerHTML == `{{${key}}}`) {
//更新真实DOM元素的内容为data中当前key属性的实时值
obj.elem.innerHTML = data[key]
}
}
}
Object.seal(data)