Vue基本思路
- 创建vue对象:构造函数或者class类
- 声明data层数据(data,methods)
- 创建dom对象(#app)(告诉vue解析那一部分的dom对象)(view层)
- 创建compile:解析view层
- 解析指令:v-text等
- 解析文本
- 创建observer对象:劫持data层;
- 创建watcher层
- 连接compile和observer作用
compile
创建文本碎片
- 所有操作dom在文本碎片中进行
- 处理结束之后放到body里面,再由浏览器进行解析;
- 可以避免一定程度的回流和重绘
compile方法解析node节点
- 注意区分元素节点和文本节点
- 进行递归操作:解析下一层的node
元素节点
- 主要解析指令
- 是在元素节点处进行递归解析
- 主要解析有”v-“开头指令
- 需要尤其注意v-on:click绑定事件特殊处理
文本节点
- 主要解析文本中包含此种形式的数据
正则分组
参考文件
解析完毕
解析完毕之后要将文本碎片放回body中
observer
- 主要作用通过Object.defineProperty检测data中所有的属性
- 此处依旧注意递归操作;
watcher
连接observer和compile
- 如果需要使页面更新,需要在compile中的指令解析的时候;
- 如果需要检测数据改变,需要在observer中的数据劫持的set中进行;
所以就需要
- 在更改dom对象值的时候使用watcher检测:声明watcher对象;
1 |
|
- 如果需要更改调用回调:在watcher内部需要一个方法来调用callback;
1 |
|
- 需要知道在什么时候调用update:数据改变的时候-也就是observer中的set方法调用的时候
问题:
- 我们是在compile中实例化的watcher,需要在observer中调用watcher中的updata方法
- 而且每一个数据在compile过程中,可能不只有一个watcher对象
data.msg==>=>v-test=>v-html;
- data中的每一个key,都需要一个对象挂载上他自己的watcher对象
实现步骤
需要在observer中劫持data中的每一个属性的时候,声明一个Dep(挂载此属性下watcher)对象
1 | let dep = new Dep(); |
需要每个watcher在实例化的时候把自己放到Dep中的一个属性里面:;
1 | class Dep { |
先把watcher挂载到一个对象上面,要求在observer中也能拿到:window可以,此处用的是dep本身;
1
2
Dep.target = this;//此处的this就是watcher实例化之后的对象在wathcer中调用获取oldValue的时候就会触发get方法,此时把我们挂载到Dep中的watcher放到dep中的subs数组中
1 | Dep.target && dep.addSub(Dep.target) |
解析总结
整个完成之后data中的每一个属性都会有自己一个Dep,Dep中的subs包含着凡是用到过此属性的所有watcher;
在data发生改变之后
- 首先触发的是observer中的set方法;
- 调用dep中的发布函数:notify
- 发布函数会通知subs中的所有watcher调用自身的update函数
- watcher中的updata会触发回调,改变元素的值;