核心
本章节主要致力于Vue的核心实现
图解Vue核心
Vue的核心是Object.defineProperty+发布订阅模式。利用defineProperty劫持数据层的数据。当视图层用到数据层的数据时,利用发布订阅模式,在代理中添加一对多的依赖,视图层的多个模块依赖于一个数据层中的数据;当数据层的数据发生变化时,再次利用defineProperty劫持数据,通知所有依赖于该数据的视图层模块进行视图更新。
首先,我们先对Vue进行拆解,Vue可以分为以下几个类:
- Vue类:入口,主要负责初始化各个实例以及做一些代理任务,例如代理vue.data.msg为vue.msg
- Observer类:主要负责数据层的data中各个属性的数据劫持,创建与各个属性绑定的代理Proxy实例。在get中添加依赖与数据层中数据的视图模块(Watcher),在set中通知依赖于数据层中对应数据的视图层更新视图
- Compiler类:负责节点上的指令,内部利用Watcher建立视图层与数据层连接,最后渲染视图
- Proxy类:主要负责视图层与数据层的依赖订阅,以及数据层修改通知视图层更新,即发布订阅模式中的中间代理。
- Watcher类:主要负责获取对应视图层在数据层中的数据,从而建立视图层与数据层的连接
创建一个Vue实例会经过以下几个过程:
- 调用构造函数进行初始化
- 在构造函数中实例化Observer,为数据层中的data中的属性绑定defineProperty
- 在构造函数中实例化Compiler,解析标签中的指令,并且渲染视图
现在我们对过程2进行分解后,会经历以下几个过程:
- 为数据层中所有data中的属性绑定defineProperty
- 创建一个代理Proxy实例,用于管理订阅与发布
- 在defineProperty内部调用get(订阅subscribe)时,为数据层data中的属性绑定对应于视图的Watcher
- 在defineProperty内部调用set(发布publish)时,通知该属性下的proxy实例通知所有Watcher重新渲染视图
现在我们对过程3进行分解后,会经历以下几个过程:
- 分析指令的类型做出不同使用不同方法编译节点
- 为节点添加Watcher
- Watcher将与数据层的data绑定,即做到了数据层与视图层绑定
- Watcher将从数据层获取的数据返回给Compiler,Compiler最后在负责渲染视图,实现了真正的数据与视图绑定
以下是整体的流程图:
以下是调用数据层中get的结果:
Proxy负责添加负责提供视图更新数据的Watcher,建立依赖,让Watcher与数据层绑定
以下是调用数据层中set的结果:
Proxy负责通知负责提供视图更新数据的Watcher,让Watcher重新从数据层获取数据,然后让Compiler渲染视图
// 为Vue实例中data中的属性定义defineProperty
class Observer {
}
// 编译vue文件中的节点上的指令与Vue实例中的data建立连接
class Compiler {
constructor() {
let node = this.compiler();
parent.appendChild(node);
}
compiler() {
}
}
class Watcher {
}
// 发布订阅模式中的代理,用于管理添加依赖与通知
class Proxy {
constructor() {
this.map = {};
}
subscribe() {
}
notify() {
}
}
class Vue {
constructor(options) {
this.$data = options.data || {};
this._proxyData(this.$data);
}
/*
使用Object.defineProperty来管理当Vue中的data
*/
_proxyData(data) {
}
}
至此,一个极简的Vue实现了,其中还存在许多问题,例如data应该使用函数等等。更多内容将后续更新~🐞