Vue3 Composition API介绍及实现原理分析

一、Vue3 Composition API是什么?

Composition API是Vue3中核心逻辑及代码组织方法。Vue核心团队将Composition API描述为:一组基于功能的附加API,可以灵活的组合组件的逻辑。在基于Vue2开发项目时,通过methods、watch、data等组件属性实现页面逻辑的方式称之为Option API。Option API模式不仅导致组件业务分散、产生胶水代码,而且编写的代码也需要Vue编译器将JS代码转换为真正的执行代码。Composition API通过将组件属性作为JS函数暴露出来以解决上述问题,通过Composition API实现的业务代码无需编译器中间处理,同时TypeScript的类型检查机制可以更好的保障代码的健壮。

Vue3 Composition API介绍及实现原理分析_第1张图片

图1 Composition API主要功能函数

二、通过例子了解Composition API使用方式

Vue3 Composition API介绍及实现原理分析_第2张图片

在这个mini版本的TodoList组件中,首先引入了reactive、Refs、onMounted三个函数,其中reactive主要是用来创建响应式对象,toRefs主要是解决响应式对象因解构赋值导致响应式失效的问题,onMounted则用来访问mounted挂载组件时的钩子函数。

其次,定义DataPros的接口类型,通过这个接口类型可以获取reactive中定义的属性类型及函数的参数、返回值类型。setup函数是一个新的Vue组件对象,是组件使用Composition API的入口,setup函数包含两个参数,第一个是用来获取父组件传值的props,第二个content参数代表组件的上下文对象。这里需要注意的是this在setup中无法使用。在setup中我们定义了一个数据类型为DataProps名称为data的响应式对象,对象内包含两个参数和两个业务方法,这些定义的属性和方法都在reactive创建的响应式对象中,从而避免了参数定义和逻辑定义分离的问题。

最后,通过toRefs组件,对data对象进行包装,使其在解构赋值后不会丢失响应式特性,并通过return将数据合并到组件模板渲染上下文。

三、使用Composition API模块化共享属性和方法

在Vue2项目中,若想在别的组件共享一些属性和代码可以通过mixins(混入)和scoped slots这两种方式实现,但是这两种方式都存在缺陷。mixins最大的缺陷在于我们对其在组件中注入的属性和方法一无所知,更无法实现类型推断,且混入的内容可能与当前组件存在冲突(Vue2有一套完善的优先级排列,但熟记较有难度)。scope slots通过v-slot属性准确知道调用者获取了哪些属性,但只能在template中访问,且只能在当前组件的作用域使用。下面我们来看怎样通过Composition API共享属性和方法:

Vue3 Composition API介绍及实现原理分析_第3张图片

通过引入ref函数,创建了一个名为nowTime的属性,并创建了一个名为getNowTime的方法,然后我们就可以在任意组件中通过import的方式进行代码共享。这种共享代码的方式既不受模板和组件范围的限制,也将受益于编译器类型检查机制。值得一提的是,在Vue3中Vuex也可以采用此函数式的方式引用,无需污染Vue原型。

四、Composition API响应式对象实现源码分析

在Vue3 Composition API中,创建响应式对象可以通过reactive API和ref API来实现,接下来我们将通过源码分析reactive API创建响应式对象的方式(ref API的实现核心也是基于reactive API)。

Vue3 Composition API介绍及实现原理分析_第4张图片

在GitHub上拉取vue-next仓库,能查看Vue3的源代码。展开vue-next/packages/reactivity/src/reactive.ts路径,能看reactive函数的定义。通过reactive的类型声明,我们可以看到函数接收一个类型为泛型T的参数,而这个泛型继承自object,故target的类型为object类或为其子类。返回类型为UnwrapNestedRefs类型,该类型将判断返回的对象是否继承自Ref对象,如果为否则可能为嵌套的Ref对象,需用递归解套。进入reactive函数内部,我们看到如果传入的对象为只读则返回对象本身,否则返回createReactiveObject,执行创建响应式对象。

Vue3 Composition API介绍及实现原理分析_第5张图片

在createReactiveObject函数中,会判断target对象是否为对象类型,如果不是则直接返回,开发模式下会在控制台打印警告。接着会判断目标是否已经为Proxy对象,是的话同样返回。通过以上检查后,代码会创建一个新的proxy对象来实现对象的响应式,proxy对象会根据对象的类型选择使用collectionHandlers还是baseHandlers。

创建响应式对象核心在于实现get、set以及其他相关的陷阱函数,reactive基于Proxy实现了这些陷阱函数,并解决了因使用Object.defineProperty()方法导致的对象属性添加删除、组件下标修改等操作无法被监听的问题。鉴于篇幅原因,本文仅分析baseHandlers包装响应式数据的实现原理。

Vue3 Composition API介绍及实现原理分析_第6张图片

Vue3 Composition API介绍及实现原理分析_第7张图片

createGetter对象用来生成响应式对象的get方法(即get陷阱函数),通过Reflect反射获取到对象的原始属性以后,会判断对象是否为内置方法,如果为内置方法则不进行代理操作,并在属性不为readOnly的情况下执行依赖收集操作,最后通过递归调用,返回响应式get对象。

Vue3 Composition API介绍及实现原理分析_第8张图片

接下来我们来看reactive如何实现对象的set陷阱函数。函数首先会判断原来的数据是否为ref对象,若为是则直接将新数据赋值给ref.value即可(这便是用reactive创建的响应式数据不需要用.value取值的原因)。程序会判断key是否存在,如果不存在则通过trigger执行ADD操作,否则通过trigger执行SET操作。Trigger方法在框架中扮演通信员的角色,贯穿整个系统,使得ref 具有高度的响应性。

五、总结

本文以”什么是Composition API”开篇,介绍了Composition API的具体内容及优势;然后通过使用Composition API创建的mini TodoList组件,了解了Composition API的使用方式及如何通过组件化共享代码。最后,通过源码分析了reactive API的实现方式。本文旨在通过分析Composition API来帮助大家更好的理解Vue3前端框架,由于认识的局限性可能存在相应疏漏,望大家批评指正。

你可能感兴趣的:(前端,源码,vue3)