这是我参与2022首次更文挑战的第5天,活动详情查看:2022首次更文挑战
一、辅助对象compileUtil的实现
上次说到辅助对象compileUtil对象里面有不同的方法,都是接受上面传来的参数们,这些方法都是为了从data中拿到对应的值然后调用一个公共的赋值的方法来赋值更新,以下就是该辅助对象的实现:
const compileUtil = { // 辅助编译
getVal (expr, vm) { // 不断的.下去直到拿到真正的值
return expr.split('.').reduce((data, currentVal) => {
return data[currentVal];
}, vm.$data)
},
text (node, expr, vm) {
let value;
if (expr.indexOf('{{') !== -1) { // 处理{{}}
value = expr.replace(/\{\{(.+?)\}\}/g, (...args) => {
return this.getVal(args[1], vm);
})
} else {
value = this.getVal(expr, vm); // 处理v-text
}
this.updater.textUpdater(node, value); // 在上面不同情况拿到值后直接更新视图即可
},
html (node, expr, vm) {
const value = this.getVal(expr, vm);
this.updater.htmlUpdater(node, value);
},
model (node, expr, vm) {
const value = this.getVal(expr, vm);
this.updater.modelUpdater(node, value);
},
on (node, expr, vm, eventName) {
let fn = vm.$options.methods && vm.$options.methods[expr]; // 拿到对应的方法
node.addEventListener(eventName, fn.bind(vm), false); // 添加方法记得绑定到当前vue实例
},
updater: {
textUpdater(node, value) {
node.textContent = value;
},
htmlUpdater(node, value) {
node.innerHTML = value;
},
modelUpdater(node, value) {
node.value = value;
}
}
}
截止到目前我们这个简易的Vue已经可以解析编译出指令和{undefined{}}包裹的内容了。
二、实现observer劫持并监听所有属性
接下来是针对实例化传入的数据做一个劫持和监听。注意记得递归遍历完所有的数据,一个属性对应一个观察者。
class observer {
constructor (data) {
this.observe(data);
}
observe(data) { // 对数据做一个递归遍历去调用监听方法
if (data && typeof data === 'object') {
Object.keys(data).forEach((key) => {
this.defineReactive(data, key, data[key]); // 住:data = data[key]
})
}
}
defineReactive(obj, key, value) { // 劫持和监听数据
this.observe(value); // 首先需要遍历当前数据(因为可能多嵌套)
Object.defineProperty(obj, key, {
enumerable: true,
configurable: false,
get() {
return value;
},
set: (newVal) => {
this.observe(newVal); // 更新对象时再监听一遍防止新对象没有被监听到
if (newVal !== value) {
value = newVal;
}
}
})
}
}
再往下就是观察者watcher和依赖收集器Dep了,它们的实现依然留到下次具体展开,胜利就在眼前,加油!