Vue2响应式系统之嵌套怎么实现
导读:本文共4247字符,通常情况下阅读需要14分钟。同时您也可以点击右侧朗读,来听本文内容。按键盘←(左) →(右) 方向键可以翻页。
摘要: 1、场景在开发中肯定存在组件嵌套组件的情况,类似于下边的样子。Vue<!--parent-component--><div><my-component:text="inner"></my-component>{{text}}<div><!--my-component... ...
目录
(为您整理了一些要点),点击可以直达。1、场景
在开发中肯定存在组件嵌套组件的情况,类似于下边的样子。Vue
<!--parent-component--><div><my-component:text="inner"></my-component>{{text}}<div><!--my-component--><div>{{text}}</div>
回到我们之前的响应式系统,模拟一下上边的情况:
import{observe}from"./reactive";importWatcherfrom"./watcher";constdata={text:"hello,world",inner:"内部",};observe(data);constupdateMyComponent=()=>{console.log("子组件收到:",data.inner);};constupdateParentComponent=()=>{newWatcher(updateMyComponent);console.log("父组件收到:",data.text);};newWatcher(updateParentComponent);data.text="hello,liang";
可以先分钟考虑一下上边输出什么?1
首先回忆一下会做什么操作。new Watcher
第一步是保存当前函数,然后执行当前函数前将全局的赋值为当前对象。Dep.target
Watcher
接下来执行函数的时候,如果读取了相应的属性就会触发,从而将当前收集到该属性的中。getter
get
Watcher
Dep
2、执行过程
import{observe}from"./reactive";importWatcherfrom"./watcher";constdata={text:"hello,world",inner:"内部",};observe(data);constupdateMyComponent=()=>{console.log("子组件收到:",data.inner);};constupdateParentComponent=()=>{newWatcher(updateMyComponent);console.log("父组件收到:",data.text);};newWatcher(updateParentComponent);data.text="hello,liang";
我们再一步一步理清一下:
new Watcher(updateParentComponent);
将赋值为保存了函数的。Dep.target
updateParentComponent
Watcher
接下来执行函数。updateParentComponent
new Watcher(updateMyComponent);
将赋值为保存了函数的。Dep.target
updateMyComponent
Watcher
接下来执行函数。updateMyComponent
constupdateMyComponent=()=>{console.log("子组件收到:",data.inner);};//读取了inner变量。//data.inner的Dep收集当前Watcher(保存了`updateMyComponent`函数)
constupdateParentComponent=()=>{newWatcher(updateMyComponent);console.log("父组件收到:",data.text);};//读取了text变量。//data.text的Dep收集当前Watcher(保存了`updateMyComponent`函数)
data.text = "hello, liang";
触发的函数,执行它依赖的,而此时是函数。text
set
Watcher
updateMyComponent
所以上边代码最终输出的结果是:
子组件收到: 内部 // new Watcher(updateMyComponent); 时候输出
父组件收到: hello, world // new Watcher(updateParentComponent); 时候输出
子组件收到: 内部 // data.text = "hello, liang"; 输出
然而子组件并不依赖,依赖的父组件反而没有执行。data.text
data.text
3、修复
上边的问题出在我们保存当前正在执行时候使用的是单个变量。Watcher
Dep.target = null; // 静态变量,全局唯一
回忆一下学习语言或者汇编语言的时候对函数参数的处理:C
functionb(p){console.log(p);}functiona(p){b("child");console.log(p);}a("parent");
当函数发生嵌套调用的时候,执行函数的时候我们会先将参数压入栈中,然后执行函数,同样将参数压入栈中,函数执行完毕就将参数出栈。此时回到函数就能正确取到参数的值了。a
b
b
a
p
对应于的收集,我们同样可以使用一个栈来保存,执行函数前将压入栈,执行函数完毕后将弹出栈即可。其中,始终指向栈顶,代表当前正在执行的函数。Watcher
Watcher
Watcher
Dep.target
Watcher
回到代码中,我们提供一个压栈和出栈的方法。Dep
import{remove}from"./util";letuid=0;exportdefaultclassDep{...省略}Dep.target=null;//静态变量,全局唯一//Thecurrenttargetwatcherbeingevaluated.//Thisisgloballyuniquebecauseonlyonewatcher//canbeevaluatedatatime.consttargetStack=[];exportfunctionpushTarget(target){targetStack.push(target);Dep.target=target;}exportfunctionpopTarget(){targetStack.pop();Dep.target=targetStack[targetStack.length-1];//赋值为栈顶元素}
然后中,执行函数之前进行入栈,执行后进行出栈。Watcher
import{pushTarget,popTarget}from"./dep";exportdefaultclassWatcher{constructor(Fn){this.getter=Fn;this.depIds=newSet();//拥有has函数可以判断是否存在某个idthis.deps=[];this.newDeps=[];//记录新一次的依赖this.newDepIds=newSet();this.get();}/***Evaluatethegetter,andre-collectdependencies.*/get(){/************修改的地方*******************************/pushTarget(this);//保存包装了当前正在执行的函数的Watcher/*******************************************/letvalue;try{value=this.getter.call();}catch(e){throwe;}finally{/************修改的地方*******************************/popTarget();/*******************************************/this.cleanupDeps();}returnvalue;}...}
4、测试
回到开头的场景,再来执行一下:
import{observe}from"./reactive";importWatcherfrom"./watcher";constdata={text:"hello,world",inner:"内部",};observe(data);constupdateMyComponent=()=>{console.log("子组件收到:",data.inner);};constupdateParentComponent=()=>{newWatcher(updateMyComponent);console.log("父组件收到:",data.text);};newWatcher(updateParentComponent);data.text="hello,liang";
执行的时候将入栈。new Watcher(updateParentComponent);
Watcher
进入函数,执行的时候将入栈。updateParentComponent
new Watcher(updateMyComponent);
Watcher
执行函数,收集当前,执行完毕后出栈。updateMyComponent
data.inner
Dep.target
Watcher
继续执行函数,收集当前。updateParentComponent
data.text
Dep.target
此时依赖就变得正常了,会触发函数,从而输出如下:data.text
updateParentComponent
子组件收到: 内部
父组件收到: hello, world
子组件收到: 内部
父组件收到: hello, liang
</div> <div class="zixun-tj-product adv-bottom"></div> </div> </div> <div class="prve-next-news">
Vue2响应式系统之嵌套怎么实现的详细内容,希望对您有所帮助,信息来源于网络。