这里对事件绑定进行了简化,只保留了on off emit三个方法:
class Event { constructor() { this.collector = Object.create(null); } on(eName, cb) { this.collector[eName] ? this.collector[eName].push(cb) : (this.collector[eName] = [cb]); } off(eName, cb) { if (!(eName && cb)) { this.collector = Object.create(null); } else if (eName && !cb) { delete this.collector[eName]; } else { this.collector[eName].splice(this.collector[eName].indexOf(cb), 0); } return this; } emit(eName, ...arg) { for (const cb of this.collector[eName]) { cb(...arg); } } } const eventBinder = new Event(); export { eventBinder }; export default eventBinder.emit.bind(eventBinder); //! emit会被注册到vm上,让它的this始终指向eventBinder 更新页面有了渲染函数就可以根据数据的变化来渲染页面了,如果一次有多个数据进行修改,那么会触发多次渲染函数,这是明显的性能浪费,所以引用任务队列和锁的概念来保证一次操作只会重新渲染一次页面:
// Dep.js export default class Dep { constructor() { this.lock = true; } notify(vm) { //? onBeforeUpdate //! 把更新视图放到微任务队列,即使多个数据改变也只渲染一次 if (this.lock) { this.lock = false; //! 应该在这里运用diff算法更新DOM树 这里只是重新渲染一次页面 nextTick(render, vm); nextTick(() => (this.lock = true)); //? onUpdated } } } // nextTick.js export default function nextTick(cb, ...arg) { Promise.resolve().then(() => { cb(...arg); }); } 结语代码地址
说不定还会试着加入其它功能。