博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
图解vueVue响应式原理
阅读量:7016 次
发布时间:2019-06-28

本文共 4292 字,大约阅读时间需要 14 分钟。

本文是受

启发自行绘制的vue动态响应原理图解 画风诡异,仅代表个人理解如果有不当的地方,望请斧正。

官方大图

我的见解

JserWang的原理代码,为了看懂我自行添加了好多注释与console。

//3.const Observer = function(data) {  // 循环修改为每个属性添加get set  for (let key in data) {    console.log("给value的没一个key设置一个收集器");    defineReactive(data, key);  }}//4.const defineReactive = function(obj, key) {  // 局部变量dep,用于get set内部调用  console.log("创建收集器***********");  const dep = new Dep();  // 获取当前值  let val = obj[key];  console.log("observe  开始重写data每个属性的get/set");  Object.defineProperty(obj, key, {    // 设置当前描述属性为可被循环    enumerable: true,    // 设置当前描述属性可被修改    configurable: true,    get() {      console.log('observe get触发');      // 调用依赖收集器中的addSub,用于收集当前属性与Watcher中的依赖关系      console.log("observe dep.depend收集当前属性和watcher的依赖关系");      console.log("当^^^^^^^^^^^^^^^^^^^^^^^^前属性:", key);      dep.depend();      return val;    },    set(newVal) {      if (newVal === val) {        console.log("observe set 设置属性值未变化");        return;      }      val = newVal;      // 当值发生变更时,通知依赖收集器,更新每个需要更新的Watcher,      // 这里每个需要更新通过什么断定?dep.subs      console.log("observe 设置属性值变化通知依赖收集器更新watcher");      dep.notify();    }  });}const observe = function(data) {  return new Observer(data);}//1.const Vue = function(options) {  const self = this;  self.a = 1;  self.b = 1;  // 将data赋值给this._data,源码这部分用的Proxy所以我们用最简单的方式临时实现  if (options && typeof options.data === 'function') {    console.log("Vue 将传入配绑定给新建的vue对象:", this);    this._data = options.data.apply(this);  }  // 挂载函数  this.mount = function() {    let tmp = self.a;    self.a += 1;    console.log("Vue 挂载watcher实例到当前vue对象",  tmp);    new Watcher(self, self.render);  }  // 渲染函数  this.render = function() {    let tmp =  self.b;    self.b += 1;    console.log("Vue 触发渲染vue对象", tmp);    console.log('Vue 看该属性是否被组件引用,引用则重新渲染');    // with(self) {    //   _data.text;//获取当前的data中的属性    //   _data.a;    //   _data.b;    // }    console.log(self._data.text);    console.log(self._data.text1);    console.log(self._data.text2)  }  // 监听this._data  //2.  console.log("Vue 设置观察对象, 重写set、get");  observe(this._data);  }const Watcher = function(vm, fn) {  const self = this;  //保存传入的data对象  this.vm = vm;  // 将当前Dep.target指向当前watcher  console.log("Watcher 将当前Dep.target指向当前watcher");  console.log("-----------------------临时关联watcher----------------------------");  Dep.target = this;  // 向Dep方法添加当前Wathcer  this.addDep = function(dep) {    console.log("watcher向当前收集器dep添加当前Wathcer");    dep.addSub(self);  }  // 更新方法,用于触发vm._render  this.update = function() {    console.log("watcher  触发render");    fn();//vue.render  }  // 这里会首次调用vm._render,从而触发text的get  // 从而将当前的Wathcer与Dep关联起来  //vue.render  首次渲染  console.log("-----------------------首次渲染----------------------------");  this.value = fn();  // 这里清空了Dep.target,为了防止notify触发时,不停的绑定Watcher与Dep,  // 造成代码死循环  console.log("————————————————————清空Dep.target");  Dep.target = null;}//5.const Dep = function() {  console.log("Dep新建收集器");  const self = this;  // 收集目标  this.target = null;  // 存储收集器中需要通知的Watcher  this.subs = [];  // 当有目标时,绑定Dep与Wathcer的关系  this.depend = function() {    //确认实例是否绑定watcher    if (Dep.target) {      // 这里其实可以直接写self.addSub(Dep.target),      // 没有这么写因为想还原源码的过程。      console.log("Dep向当前收集器dep添加当前Wathcer");      Dep.target.addDep(self);    }  }  // 为当前收集器添加Watcher  this.addSub = function(watcher) {    console.log("Dep addSub为当前收集器添加watcher");    self.subs.push(watcher);  }  // 通知收集器中所的所有Wathcer,调用其update方法  this.notify = function() {    console.log("Dep 通知所有的watcher 触发更新");    for (let i = 0; i < self.subs.length; i += 1) {      self.subs[i].update();      console.log(`第${i}个watcher`, self.subs[i]);    }  }}const vue = new Vue({  data() {    return {      text: 'hello world',      text1: "aaa",      text2: "333"    };  }})console.log("触发挂载-----------------------");vue.mount(); // in getconsole.log(vue._data.text);console.log(vue._data.text1);console.log(vue._data.text2);console.log('data set调用------------------------------------------------------');vue._data.text = '123'; // in watcher update /n in getconsole.log('data set调用-----------------------------------------------------------------');vue._data.text = 'aaaaa';console.log(vue._data.text);console.log(vue._data.text1);console.log(vue._data.text2);复制代码

转载于:https://juejin.im/post/5cadb656e51d456e651b644f

你可能感兴趣的文章
[SDOI2010]星际竞速——费用流
查看>>
C#开发串口总结,并提炼串口辅助类到公用类库中
查看>>
【个人笔记】《知了堂》MySQL中的数据类型
查看>>
Java “Unhandled exception type Exception”错误提示 (转)
查看>>
PHP源码之explode分析
查看>>
怪叔叔 一路走好 下辈子我们再一起玩KOF
查看>>
B.华华教月月做数学
查看>>
python 如何自动发送测试报告
查看>>
网络流24题4
查看>>
【第一组】第十一次例会纪要
查看>>
Hamming Weight的算法分析
查看>>
yii2 数据库操作详解(转载)
查看>>
JS函数
查看>>
c语言判断用户是否输入-非阻塞函数kbhit
查看>>
Hive基础
查看>>
(转)Sharepoint学习笔记—Debug--寻找 WSS_Logging下的ULSTraceLog
查看>>
Markdown anywhere
查看>>
内置函数了解一下
查看>>
Java:关于implements Serializable的警告问题
查看>>
Windows Server 2012虚拟化性能及十大重要功能
查看>>