1. 编译器
/**
* @param el 挂载到的dom节点
* @param vm 虚拟dom
*/
function Compile(el, vm) {
this.el = document.querySelector(el);
this.vm = vm;
this.fragment = null; // 页面
this.init();
}
Compile.prototype = {
init: function (){
if(this.el) { // 节点存在
this.fragment = this.nodeToFragment(this.el); // 生成页面
this.compileElement(this.fragment); // 编译页面
this.el.appendChild(this.fragment); // 将页面渲染到节点
} else {
console.log('未设置DOM节点');
return;
}
},
nodeToFragment: function () {
var fragment = document.createDocumentFragment(); // 创建虚拟节点
var child = el.firstChild(); // 孩子节点
while(child) { // 遍历孩子节点
fragment.appendChild(child);
child = el.firstChild();
}
return fragment;
},
compileElement: function (el) { // 编译DOM元素
var self = this;
var childNodes = el.childNodes;
[].slice.call(childNodes).forEach(function(node) {
var reg = /{{(.*)}}/; // 匹配{{}}
var text = node.textContent;
if (self.isTextNode(node) && reg.test(text)) { // 如果是文本节点
self.compileText(node, reg.exec(text)[1]); // ↓找下面的方法编译替换模板数据
}
if (node.childNodes && node.childNodes.length) { // 还存在节点就递归
self.compileElement(node);
}
})
},
isTextNode: function(node) {
return node.nodeType == 3;
},
compileText: function(node, exp) {
var self = this;
var initText = this.vm[exp];
this.updateText(node, initText);
new Watcher(this.vm, exp, function(value) {
self.updateText(node, value);
})
},
updateText: function(node,value) {
node.textContent = typeof value == 'undefined' ? '': value;
},
isDirective: function(attr) {
return attr.indexOf('v-') == 0;
},
isEventDirective: function(dir) {
return dir.indexOf('on:') === 0;
},
isElementNode: function (node) {
return node.nodeType == 1;
}
}