Vue源码整理, 数据代理和响应式

最近看了一下Vue相关的东西 ,整理一下流程:

1. 数据代理 -> Object.defineProperty()

  let vm = new Vue({	
   	data:{
   		a:0
   	}
   })
   // 为什么能通过 vm.a 访问到 data 中的 a ?
   // 因为会通过 Object.defineProperty 设置了数据代理
   Object.defineProperty(vm, 'a', {
   	get(){
           return data.a
       },
    set(val){
       	data.a = val
  	   }
   })	

2. 模板解析 -> NodeType -> Reg -> {{}} -> v-on -> bind/html/class/text

Vue 2 是虚拟节点VNode

  let vm = new Vue({	
      el: '#my',
  	data:{
  		a:0
  	}
  })
  // 拿到 el 对应的模板以后, createDocumentFragment() 产生一个Dom片段
  // 再将el所有子节点插入到该Fragment
  // 遍历Fragment中每个节点
  // 文本 => 匹配{{}}
  // 元素 => 编译元素的指令
  // 普通指令/事件指令 => 编译完后删除该指令
  // 包含子节点 => 继续迭代 

3. 数据绑定和响应式 -> 使用数据劫持的技术实现

一旦更新data中某个属性数据, 所有界面直接使用或间接使用该属性的节点会更新
基本思路: 通过defineProperty监视data中所有层级数据的变化, 变化则更新界面

vm.a = 3
=> vm.a.set // 更新data中的a
=> vm.data.a = 3
=> vm.data.a.set //更新界面
增加observe => 递归对每个属性 Object.defineProperty 增加 get set, 并且设为configurable:false
除了事件指令, 每个指令/表达式 => 增加watcher

Dep -> {
	实例创建时间 => 给data中每个属性增加observe数据劫持时(增加get,set)创建的, 在模板编译之前, new watcher()以前
	数量 => 与data中属性一一对应(所有层级)
	结构 => {
		id: 标识 uid
		subs: [] subscribe订阅者数组, 内容是 watchers // 即需要更新的所有相关表达式
	}
}
watcher -> {
	实例创建时间 => 初始化解析大括号表达式/一般指令时创建
	数量 => 与大括号表达式/一般指令一一对应
	结构 => {
		cb: cb 界面更新回调
		vm: vm
		exp: 对应的表达式
		depIds: {} 相关的n个dep      // 主要用于判断关系是否建立, 避免再次建立dep watcher关系
		value: get() 当前表达式value
	}
}

Dep与Watcher关系
关系 ->
	data属性 -> 一个dep -> n个watcher(属性在模板多次使用)
	表达式 -> watcher -> n个dep(多层表达式, 如a.b, 对应了两个dep)
建立 ->
	初始化data数据 -> 每个数据增加dep, 并增加 get, set -> 编译模板 -> 拿到表达式 -> 每个表达式增加一个watcher -> watcher初始化会有个value属性 -> 该value属性调用了dep的get方法 -> dep的get方法depend() -> 通过watcher的depIds判断关系是否建立 -> dep 保存watcher到subs -> watcher 的depIds保存dep
响应式 ->
	vm.name = 'abc' -> data中name属性值变化 -> name的 set() -> dep.notify()  -> dep中subs数组中每个watcher进行update() -> watcher.cb 回调 -> updater更新界面


总结

整体实现分为已下步骤

  1. 实现一个Observer,对数据进行劫持,通知数据的变化(将使用的要点为:Object.defineProperty()方法)
  2. 实现一个Compile,对指令进行解析,初始化视图,并且订阅数据的变更,绑定好更新函数
  3. 实现一个Watcher,将其作为以上两者的一个中介点,在接收数据变更的同时,让Dep添加当前Watcher,并及时通知视图进行update
  4. 实现一些VUE的其他功能(Computed、menthods)
  5. 实现MVVM,整合以上几点,作为一个入口函数

在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/zdhanunity/article/details/94549127