Vue.js的MVVM的响应式原理-指令解析&初始化视图
Vue.js采用数据劫持结合发布者-订阅者模式的放方式,通过Object.defineProperty()来劫持各个属性的setter,getter,在数据变动时发布消息给订阅者,触发响应的监听回调

Vue.js内部指令解析和视图初始化

//MVue.js
const compileUtil = {
getValue(expr, vm){
//[person,name]
return expr.split('.').reduce((data,currentVal)=>{
return data[currentVal];
},vm.$data)
},
text(node,expr,vm){ //expr:msg 学习MVVM实现原理 //三种情况 v-text="msg" v-text="person.name" {{}}
// console.log(expr);
let value;
if(expr.indexOf("{{") > -1){
//{{Person.name}}--{{Person.age}}
value = expr.replace(/\{\{(.+?)\}\}/g, (...args)=>{
return this.getValue(args[1], vm);
})
}else{
value = this.getValue(expr, vm);
}
this.updater.textupdater(node, value);
},
html(node,expr,vm){
const value = this.getValue(expr, vm);
this.updater.htmlUpdater(node, value);
},
model(node,expr,vm){
const value = this.getValue(expr, vm);
this.updater.modelUpdater(node, value);
},
on(node,expr,vm,eventName){
let fn = vm.$options.methods[expr];
node.addEventListener(eventName, fn.bind(vm), false);
},
bind(node, expr, vm, attrName){
//
},
//更新的函数
updater:{
textupdater(node, value){
node.textContent = value;
},
htmlUpdater(node, value){
node.innerHTML = value;
},
modelUpdater(node, value){
node.value = value;
}
}
}
class Compile{
constructor(el,vm){
this.el = this.isElementNode(el) ? el : document.querySelector(el);
this.vm = vm;
//1.获取文档碎片 放入内存中会减少页面的回流和重绘
const fragment = this.node2Fragment(this.el);
console.log(fragment)
//2.编译模板
this.compile(fragment);
//3.追加子元素到根元素
this.el.appendChild(fragment);
}
compile(fragment){
//1.获取子节点
const childNodes = fragment.childNodes;
[...childNodes].forEach(child=>{
// console.log(child)
if(this.isElementNode(child)){
//是元素节点
//编译元素节点
// console.log("元素节点", child)
this.compileElement(child);
}else{
//文本节点
//编译文本节点
// console.log("文本节点", child)
this.compileText(child);
}
//递归遍历内部节点
if(child.childNodes && child.childNodes.length){
this.compile(child);
}
})
}
//编译元素节点
compileElement(node){
const attributes = node.attributes;
// console.log(attributes);
[...attributes].forEach((attr)=>{
const {name, value} = attr;
// console.log(name);
if(this.isDirective(name)){ //是一个指令 v-textv-html v-model v-on:chilk
const [,dirctive] = name.split('-'); // text html model on:click
const [dirName, eventName] = dirctive.split(':'); // text html model on
// 更新数据 数据驱动视图
compileUtil[dirName](node, value, this.vm, eventName)
// 删除有指令的标签的属性
node.removeAttribute('v-'+ dirctive);
}else if(this.isEventName(name)){ // @click="handlerClick"
let [,eventName] = name.split("@");
compileUtil["on"](node, value, this.vm, eventName);
}
})
}
//判断是否是@符号开头
isEventName(attrName){
return attrName.startsWith("@");
}
//判断是不是一个指令
isDirective(attrName){
return attrName.startsWith("v-");
}
//编译文本节点
compileText(node){
// {{}} v-text
const content = node.textContent;
if(/\{\{(.+?)\}\}/.test(content)){
compileUtil['text'](node, content, this.vm)
}
}
node2Fragment(el){
//创建文档碎片
const f = document.createDocumentFragment();
let firstChild;
while(firstChild = el.firstChild){
f.appendChild(firstChild);
}
return f;
}
//判断是否是元素节点
isElementNode(node){
return node.nodeType === 1;
}
}
class MVue{
constructor(options){
this.$el = options.el;
this.$data = options.data;
this.$options = options;
if(this.$el){
//1.实现一个数据的观察者
//2.实现一个指令解析器Compile
new Compile(this.$el, this);
}
}
}
持续更新ing...

浙公网安备 33010602011771号