这是我参与2022首次更文挑战的第7天,活动详情查看:2022首次更文挑战
一、实例化观察者时机
上次说到观察者实例化的时机,可以看到应该是在compiler类中订阅数据变化,所以在test、html等等方法中可以实例化观察者,以下是具体的实现。
getVal (expr, vm) { // 不断的通过.访问下去直到拿到真正的值
return expr.split('.').reduce((data, currentVal) => {
return data[currentVal];
}, vm.$data)
},
getContentVal (expr, vm) {
return expr.replace(/\{\{(.+?)\}\}/g, (...args) => {
return this.getVal(args[1], vm);
})
},
text (node, expr, vm) {
let value;
if (expr.indexOf('{{') !== -1) { // 处理{{}}
value = expr.replace(/\{\{(.+?)\}\}/g, (...args) => {
new watcher(vm, args[1], (newVal) => {
this.updater.textUpdater(node, this.getContentVal(expr, vm));
})
return this.getVal(args[1], vm);
})
} else {
value = this.getVal(expr, vm); // 处理v-text
new watcher(vm, expr, (newval) => {
this.updater.textUpdater(node, newval);
})
}
this.updater.textUpdater(node, value); // 在上面不同情况拿到值后直接更新视图即可
},
html (node, expr, vm) {
const value = this.getVal(expr, vm);
new watcher(vm, expr, (newval) => {
this.updater.htmlUpdater(node, newval);
})
this.updater.htmlUpdater(node, value);
},
model (node, expr, vm) {
const value = this.getVal(expr, vm);
new watcher(vm, expr, (newval) => {
this.updater.modelUpdater(node, newval);
})
this.updater.modelUpdater(node, value);
}
二、实现双向的数据绑定和proxy代理
给input输入框添加一个input事件实现视图更改数据:
setVal (expr, vm, inputVal) { // 设置输入框输入的值
return expr.split('.').reduce((data, currentVal) => {
return data[currentVal] = inputVal; // 给老值赋值输入框的值
}, vm.$data)
},
model (node, expr, vm) {
const value = this.getVal(expr, vm);
new watcher(vm, expr, (newval) => { // 数据更改视图
this.updater.modelUpdater(node, newval);
})
node.addEventListener('input', (e) => { //视图更改数据
this.setVal(expr, vm, e.target.value);
})
this.updater.modelUpdater(node, value);
}
至于代理的话是想要直接就this.属性不需要this.$data.属性,这就可以在大类里面声明一个代理的方法,具体只需要遍历所有的data去劫持返回在数据中的data:
proxyData(data) {
for(const key in data) {
Object.defineProperty(this, key, {
get() {
return data[key];
},
set(newVal) {
data[key] = newval;
}
})
}
}
至此就已经实现了MVVM原理,亲手构建起一个简易的Vue框架,各位也可以试试看自己搭建的框架与Vue有什么差别,各位加油!