基于Vue3.0在GitHub上发布的第一个版本的源代码(2019.10.05)
基本原理
ES6代理,整个响应系统的基础。目前还没有关于新的composition-API的基本用法的中文文档,可以通过这个仓库(composition-api-rfc)知道,也有相应的在线文档。先运行Vue3.0
首先克隆vue-next仓库的代码,安装依赖项,然后构建它。在vue包下的dist目录中找到构建的脚本并导入该脚本。下面演示一个简单的计数器:
!DOCTYPE html html lang=' en ' body div id=' app '/div/body script src=' http :/dist/Vue . global . js '/script script const { createApp,reactive,computed }=Vueconst root component={ template : ` button @ click=' increment ' Count为: {{ state.count }} /button `,setup(){ const state=reactive({ Count : 0,0 })函数increment() { state.count }返回{ state,Growth}}} createapp()。mount (rootcomponent,' # app')/script/htmltemplate与以前相同。同样,Vue3也支持手写渲染。当模板和渲染同时存在时,首选渲染。
设置选项是一个新的重大变化。顾名思义,安装函数将在组件安装之前运行一次(在创建之前和创建生命周期之间)。与组件初始化的功能类似,安装程序需要返回一个对象或函数。返回的对象将被分配给组件实例的renderContext,可以在组件的模板范围内访问,类似于数据的返回值。返回函数被视为程序集的呈现。具体来说,可以仔细看文档。
reactive的功能是将一个对象打包成一个响应对象,用Proxy表示。
在上面的计数器示例中,在组件的设置函数中,创建了一个包含计数属性的响应对象状态。然后创建一个增量函数,最后将状态和增量返回到作用域,这样模板中的按钮按钮就可以访问增量函数绑定到点击的回调,计数也可以显示在按钮上。当我们点击按钮时,按钮上的值会相应地增加。
我们开门见山吧。让我们探索按钮上的计数值跟随响应更新的原理
数据结构
首先列出一些主要的数据结构,这里先列出,后面提到可以回头看。
ReactiveEffect是一个Function对象,用于挂载和更新组件。
界面反应效果{() :有效果吗:真有效:布尔原始:函数//具体的函数deps: ArrayDep计算出来了吗?布尔调度程序?(run : Function)=void onTrack?(event : debugger event)=void onTrigger?(event : debuggeevent)=void on top? ()=void}targetMap是一种类似于{target-key-dep}的Map结构,用于缓存所有响应对象和依赖项集合。
导出类型dep=setreactieeffectexport导出类型keytodepmap=mapstring | symbol,depexport const target map : weak pany,keytodepmap=newweakmap()
反应函数将通过代理包装传入的目标对象,截取其get和set,并将代理目标缓存到targetMap,targetMap.set(target,new Map())。
代理将在得到时调用跟踪函数,集合将调用触发函数。分别对应依赖集合和触发更新。
//Proxy get简化函数get (target:any,key:string | symbol,receiver 3360 any){//获取原始值RES const RES=reflect.get (target,key,The receiver) //过滤不需要代理的情况/.//取决于收集轨道(目标、操作类型。get,key)//如果得到的值是一个对象,则再次包装该对象//代理只能表示第一级返回isObject(res)?reactive(RES): RES }//proxy set简化功能集(目标: any,键: string | symbol,值: any,Receiver : any): boolean {//某些场景没有proxy set.//设置原始对象的值const result=reflect.set(目标、键、值、接收器)//避免重复触发器的逻辑/.//触发器通知更新触发器(目标,‘更新类型,添加键或更新键’,键)返回结果}取决于收集和触发器更新
当组件处于渲染阶段时,视图会读取数据对象上的值进行渲染,此时会触发get of Proxy,这会触发相应的track函数,并记录相应的ReactiveEffect,这通常称为依赖集合。
实际上,ReactiveEffect可以看作是组件的更新(mount是一种特殊的更新),数据的变化触发触发器,遍历调用track收集的对应数据的ReactiveEffect,即对应组件的更新。
由触发器触发的组件更新会在渲染阶段触发新一轮的轨迹相关性收集和更新相关性。
//简化轨迹功能轨迹(目标:任意,类型:操作类型,键?字符串|符号){//仅在依赖项收集阶段执行依赖项收集。//其他场景可能会触发获取代理。但是没有必要收集依赖关系。//当前呈现的组件的挂载和更新逻辑被包装在ActiveReactiveEffectStack的顶部。const Effect=active reactiveeffect stack[active reactiveeffect stack]。length-1]//如果效果为空,说明如果(效果){//.//=====初始化与{ target-key-dep } let deps map=target map对应的结构。get(target)if(depsMap===void 0){ targetmap . set(target),(depsMap=new Map())} let dep=depsMap . get(key as string | symbol)if(!dep){ deps map . set(key as string | symbol,(dep=new set())}//=====初始化与{target-key-dep}对应的结构。//如果不在依赖列表中,则添加If(!Dep.has(effect)) {//这里,效果作为依赖项缓存在依赖项列表dep . add(effect)effect . deps . push(dep)}//Simplified trigger function trigger(target 3360 any,type : operation types,key?字符串|符号,extraInfo? any) {//获取依赖项const deps map=target map . get(target)const effects : setreactiveeffect=new set()//省略分类逻辑depsMap.forEach(dep={//将效果分类过滤器添加到效果中})const run=(effect : reactive effect)={//有一个异步调度进程,nextTick scheduleRun(effect,目标的常规进程,类型,键,额外信息)} effects。foreach (run)}:
摘要
目前的代码只有新特性的实现,ES6 TS的组合可读性大大提高,编辑器支持也很好,所以会相对容易阅读。在这里,我们简单梳理一下vue 3.0 reactive的整个流程,有很多细节值得学习,继续往下说。
以上就是本文的全部内容。希望对大家的学习有帮助,支持我们。