手机版

详细解释VueJS数据驱动和依赖跟踪分析

时间:2021-09-04 来源:互联网 编辑:宝哥软件园 浏览:

之前对Vue数据绑定的原理做了一点分析,最近需要复习一下,顺便发给文章

在之前自己的Mvm实现中,setter是用来观察模型的,接口上的所有viewModel都绑定到模型上。当模型改变时,更新所有视图模型并将新值呈现给界面。同时在接口上监听v-model绑定的所有输入,通过addEventListener事件将新值更新到模型中,从而完成双向绑定。

但是那个程序除了理解定义的性质之外毫无价值。

没有已编译的节点。不处理表达式依赖关系。这里我将解决表达式依赖的问题,下一节我将介绍vue模板的编译。

为数据定义getter setter

类观察者{构造函数(数据){ this。_数据=数据;走吧。_数据);}行走(数据){ Object.keys(数据)。forEach((key)={ this . definetrive(data,key,data[key])})};definetrive(VM,key,value){ var self=this;if(value type of value==' object '){ this . walk(value);} object . defineperoperty(VM,key,{ get: function() {返回值;},set:函数(newVal) { if (value!=NewVal){ if(NewVal type of NewVal==' object '){ self . walk(NewVal);} value=newVal} } })} } module . exports=Observer;这样,为每个属性添加getter和setter,当属性是对象时,它被递归添加。

获取或分配属性值后,将触发获取或设置。当set被触发时,即模型改变时,可以发出一条消息通知所有viewModel更新。

决定性的(VM,键,值){//在闭包中存储这个属性的依赖表达式。var Dep=new Dep();var self=这个;if(value type of value==' object '){ this . walk(value);} object . defineperoperty(VM,key,{ get: function() {返回值;},set:函数(newVal) { if (value!=NewVal){ if(NewVal type of NewVal==' object '){ self . walk(NewVal);} value=newVal//通知所有viewModel更新dep . notify();}}})}那么如何定义Dep呢?

Class Dep {constructor() {//依赖项列表此。依赖关系=[];}//添加依赖项adddep(观察器){if(观察器){this。依赖项s.push(观察者);} }//通知所有依赖更新notify () {this。依赖。foreach((观察者)={观察者。update();})} } module . exports=Dep;这里的每个依赖都是一个观察者。

查看如何定义观察器

这里,每个Watcher都有一个唯一的id号,它有一个表达式和一个回调函数。

例如,表达式a b;将在get计算期间访问a和b。因为JavaScript是单线程的,所以任何时候都只有一个JavaScript代码在执行。使用Dep.target作为全局变量来表示当前Watcher表达式,然后通过compute访问a和b,触发a和b的getter,并在getter中添加Dep.target作为依赖项。

一旦a和b的集合被触发,就调用update函数来更新相关值。

var uid=0;类观察者{构造函数(viewModel,exp,callback){ this。viewModel=viewModelthis . id=uid this . exp=exp this . callback=回调;this.oldValue=this。update();} get(){ Dep。目标=这个;var RES=这个。计算(这个。视图模型,这个。exp);Dep.target=null返回res} update(){ var new value=this。get();如果(这个。旧值===新值){ return} //回调里进行师的更新操作this.callback(newValue,this。旧值);这个。旧值=新值;} compute(viewModel,exp){ var RES=替换为(viewModel,exp);返回res} }模块。导出=Watcher由于当前表达式需要在当前的模型下面执行,所以采用替换为函数来代替有了,具体可以查看另一篇随笔爪哇岛描述语言中随着的替代语法。

通过得到添加依赖

对象。define property(VM,key,{ get : function(){ var watcher=Dep。目标;如果(守望者!离开依赖项[观察器。id]){ dep。观察者;}返回值;},set:函数(newVal) { if (value!=NewVal){ if(NewVal的NewVal类型==' object '){ self。散步(纽瓦尔);} value=newValdep。notify();} }})这种添加依赖的方式实在太巧妙了。

这里我画了一个图来描述

最后通过一段代码简单测试一下

const Observer=require(' ./观察者。js’);const Watcher=require(' ./watcher。js’);定义变量数据={ a: 10,b: { c: 5,d: { e: 20,} } var observe=new Observer(数据);var watcher=新的watcher(数据,' a b.c ',函数(新值,旧值){控制台。日志('新值为新值');console.log('oldValue是旧值');});控制台。日志(' \ r \ n ');console.log('a已更改为50,则expr的值应为55 ');data.a=控制台。日志(' \ r \ n ');console.log('b.c已更改为50,则expr的值应为122 ');数据。b . c=72;控制台。日志(' \ r \ n ');console.log('b.c已经重新设置了一个对象,那么expr的值应该是80 ');数据。b={ c : 30 }

好大功告成

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持我们。

版权声明:详细解释VueJS数据驱动和依赖跟踪分析是由宝哥软件园云端程序自动收集整理而来。如果本文侵犯了你的权益,请联系本站底部QQ或者邮箱删除。