vue实现简单的MVVM框架(4)
compileElement方法将遍历所有节点及其子节点,进行扫描解析编译,调用对应的指令渲染函数进行数据渲染,并调用对应的指令更新函数进行绑定,详看代码及注释说明:
因为我们的模板只含有一个文本节点#text,因此compileElement方法执行后会进入_this.compileText(node,reg.exec(node.textContent)[1]);//#text,'name'
Compile.prototype = {
nodeToFragment: function(el){
let fragment = document.createDocumentFragment();
let child;
while (child = el.firstChild){
fragment.appendChild(child);//append相当于剪切的功能
}
return fragment;
},
init: function(){
this.compileElement(this.$fragment);
},
compileElement: function(node){
let childNodes = node.childNodes;
const _this = this;
let reg = /\{\{(.*)\}\}/g;
[].slice.call(childNodes).forEach(function(node){
if (_this.isElementNode(node)){//如果为元素节点,则进行相应操作
_this.compile(node);
} else if (_this.isTextNode(node) && reg.test(node.textContent)){
//如果为文本节点,并且包含data属性(如{{name}}),则进行相应操作
_this.compileText(node,reg.exec(node.textContent)[1]);//#text,'name'
}
if (node.childNodes && node.childNodes.length){
//如果节点内还有子节点,则递归继续解析节点
_this.compileElement(node);
}
})
},
compileText: function(node,exp){//#text,'name'
compileUtil.text(node,this.$vm,exp);//#text,vm,'name'
},};
CompileText()函数实现初始化渲染页面视图(将data.name的值通过#text.textContent = data.name显示在页面上),并且为每个DOM节点添加一个监听数据的订阅者(这里是为#text节点新增一个Wather)。
let updater = {
textUpdater: function(node,value){
node.textContent = typeof value == 'undefined' ? '' : value;
},
}
let compileUtil = {
text: function(node,vm,exp){//#text,vm,'name'
this.bind(node,vm,exp,'text');
},
bind: function(node,vm,exp,dir){//#text,vm,'name','text'
let updaterFn = updater[dir + 'Updater'];
updaterFn && updaterFn(node,this._getVMVal(vm,exp));
new Watcher(vm,exp,function(value){
updaterFn && updaterFn(node,value)
});
console.log('加进去了');
}
};
现在我们完成了一个能实现文本节点解析的Compile()函数,接下来我们实现一个Watcher()函数。
实现Watcher
我们前面讲过,Observe()函数实现data对象的属性劫持,并在属性值改变时触发订阅器的notify()通知订阅者Watcher,订阅者就会调用自身的update方法实现视图更新。
Compile()函数负责解析模板,初始化页面,并且为每个data属性新增一个监听数据的订阅者(new Watcher)。
Watcher订阅者作为Observer和Compile之间通信的桥梁,所以我们可以大致知道Watcher的作用是什么。
