使用new来实例化vue对象时,去compile解析指令从而初始化视图
//实例化vue对象
class MVue{
constructor(options){
this.$el = options.el;
this.$data = options.data;
this.$options = options;
if(this.$el){
//1.实现一个数据观察者
//2.实现一个指令解析器
new Compile(this.$el,this)
}
}
}
//解析指令
class Compile{
constructor(el,vm){
this.el = this.isElementNode(el)?el:document.querySelector(el);
this.vm = vm;
//1.获取文档碎片对象,放入内存中会介绍页面的回流重绘
const fragment = this.node2Fragment(this.el);
//2.编译模板
this.compile(fragment);
//3.追加子元素到根节点
this.el.appendChild(fragment);
}
//编译模板
compile(fragment){
const childNodes = fragment.childNodes;
[...childNodes].forEach(child=>{
if(this.isElementNode(child)){
//元素节点,编译元素节点
this.compileElement(child);
}else{
//文本节点
this.compileText(child);
}
if(child.childNodes && child.childNodes.length){
//递归向下编译
this.compile(child);
}
})
}
//编译指令
compileElement(node){
const attributes = node.attributes;
[...attributes].forEach(attr=>{
const {name,value} = attr;
console.log();
//判断是否是一个指令
if(this.isDirective(name)){
const [,dirctive] = name.split('-');
const [dirName,eventName] = dirctive.split(':');
compileUtil[dirName](node,value,this.vm,eventName);
node.removeAttribute('v-'+dirctive);
}
else if(this.isEventName(name)){
let[,eventName] = name.split('@');
compileUtil['on'](node,value,this.vm,eventName);
}
else if(this.isAttrName(name)){
let [,attrName] = name.split(':');
compileUtil['bind'](node,value,this.vm,attrName);
}
})
}
//判断是否是@(v-on简写)
isEventName(attrName){
return attrName.startsWith('@')
}
isAttrName(attrName){
return attrName.startsWith(':')
}
//判断是否是vue指令
isDirective(attrName){
return attrName.startsWith('v-');
}
//编译文本
compileText(node){
const content = node.textContent;
if(/\{\{(.+?)\}\}/.test(content)){
compileUtil['text'](node,content,this.vm)
}
}
//判断是否是元素节点
isElementNode(node){
return node.nodeType==1;
}
//生成代码片段
node2Fragment(el){
const f= document.createDocumentFragment()
let firstChild;
while(firstChild = el.firstChild){
f.appendChild(firstChild);
}
return f;
}
}
//更新视图
const compileUtil={
getVal(expr,vm){
return expr.split('.').reduce((data,current)=>{
return data[current];
},vm.$data)
},
text(node,expr,vm){
//解析v-text或{{}}
let value;
if(expr.indexOf('{{')!==-1){
value = expr.replace(/\{\{(.+?)\}\}/g,(...args)=>{
return this.getVal(args[1],vm);
})
}else{
value = this.getVal(expr,vm);
}
this.updater.textUpdater(node,value);
},
html(node,expr,vm){
//解析v-html
const value = this.getVal(expr,vm);
this.updater.htmlUpdater(node,value)
},
model(node,expr,vm){
//解析v-model
const value = this.getVal(expr,vm);
this.updater.modelUpdater(node,value)
},
on(node,expr,vm,eventName){
//解析v-on或@
let fn = vm.$options.methods && vm.$options.methods[expr];
node.addEventListener(eventName,fn.bind(vm),false);
},
bind(node,expr,vm,attrName){
//解析v-bind或:
let attrValue = vm.$options.data[expr];
this.updater.bindUpdater(node,attrName,attrValue)
},
updater:{
//更新视图
textUpdater(node,value){
node.textContent = value;
},
htmlUpdater(node,value){
node.innerHTML = value;
},
modelUpdater(node,value){
node.value = value;
},
bindUpdater(node,name,value){
node.setAttribute(name,value);
}
}
}