vue3.x 新特性 - CompositionAPI

来源:http://www.chinese-glasses.com 作者:Web前端 人气:158 发布时间:2020-05-06
摘要:在调用computed()函数期间,传入一个function函数,可以得到一个只读的计算属性,示例代码如下: setup 会作为编写组件业务逻辑的主战场,各种 hook 类型的方法均需要在 setup这个作用域下

在调用computed()函数期间,传入一个function函数,可以得到一个只读的计算属性,示例代码如下:

setup 会作为编写组件业务逻辑的主战场,各种 hook 类型的方法均需要在 setup 这个作用域下调用,直接来看 RFC 中的例子:

8.2 创建可读可写的计算属性

context

isRef()用来判断某个值是否为ref()创建出来的对象;应用场景:当需要展开某个可能为ref()创建出来的值的时候,例如:

除此之外,还可以直接通过 watch 方法来观察某个 prop 的变动,这是为什么呢?答案非常简单,就是 props 本身在源码中,也是一个被 reactive 包裹后的对象,因此它具有响应性,所以在 watch 方法中的回调函数会自动收集依赖,之后当 count 变动时,会自动调用这些回调逻辑。

这个函数仅仅提供了类型推断,方便在结合 TypeScript 书写代码时,能为setup()中的props提供完整的类型推断。

隐藏了数据来源,主要体现在 mixin 中 会牺牲一些性能,主要体现在 HOC 中 可能会遇到命名冲突问题,主要体现在 mixin 中

template div !-- 4. 通过属性绑定,为标签设置字体颜色 -- h5 :Level Two/h5 /div/templatescript// 1. 按需导入 injectimport { inject } from '@vue/composition-api'export default { setup() { // 2. 调用 inject 函数时,通过指定的数据名称,获取到父级共享的数据 const themeColor = inject('globalColor') // 3. 把接收到的共享数据 return 给 Template 使用 return { themeColor } }}/script
export default { setup() { const data = useSearch() const { sortedData, sort } = useSorting return { data, sortedData, sort } }}function useSearch() { ...fetch data}function useSort { ...sort data}

了解 vue 2.x 的基本使用

props

【知乎 - Vue Function-based API RFC】

基础类型可以通过 ref 这个 api 来声明,如下:

const count = ref(0)const state = reactive({ count})console.log(state.count) // 输出 0state.count++ // 此处不需要通过 .value 就能直接访问原始值console.log(count) // 输出 1

基础类型

组件常用的指令生命周期函数computed、watch、ref 等1. 相关资源

之所以要通过 ref,是因为 js 中的基础类型传值不是引用传值,因此 vue-next 内部会自动将它封装为一个 ref 对象,其值指向原始值。当然,ref 指向引用类型也是没有问题的,其 value 指向引用类型变量的引用。

9.4 清除监视

import { onMounted, onUpdated, onUnmounted } from "vue";setup => { ... }); onUpdated; onUnmounted;}
import { watch } from '@vue/composition-api'
import { reactive } from "vue";export default { setup() { const state = reactive; function inc() { state.count++; } return { state, inc }; // 或者通过 toRefs 方法 // return { ...toRefs, inc }; }};
import { reactive } from '@vue/composition-api'// 创建响应式数据对象,得到的 state 类似于 vue 2.x 中 data() 返回的响应式对象const state = reactive({ count: 0 })

在分享 vue-next 各个子模块的实现之前,我觉的有必要比较全面的整理下 vue-next 中提出的函数式 api,了解这些的话,无论是对于源码的阅读,还是当正式版发布时开始学习,应该都会有起到一定的辅助作用。

在setup()函数内创建的watch监视,会在当前组件被销毁的时候自动停止。如果想要明确地停止某个监视,可以调用watch()函数的返回值即可,语法如下:

引用类型除了可以使用 ref 来声明,也可以直接使用 reactive,如下:

创建项目

在 vue-next 中,我们直接从 vue 导入 reactive 、computed 以及其他的 api 即可,如果在 vue2 版本上,我们还可以通过使用 composition-api 这个 plugin 来使用这些 api。

TemplateRefOne.vue中的示例代码如下:

export default { props: { count: Number }, setup => { console.log(`count is: ` + props.count) }) }}

安装 vue-cli3

vue-next 在这方面借鉴了 react hooks 的设计思想,但是从实现层来讲,它们是不一样的,主要有以下几点:

在项目中安装composition-api体验 vue3 新特性

在 vue-next 中,复用代码的逻辑本质上是利用这些 hook 来拆分业务逻辑与状态,如果你比较熟悉 react hooks 的话,应该很快就能明白我指的是什么意思。如果我们将逻辑都写在 setup 方法中,很快代码就会变得难以维护,在这方面,我们可以将一些耦合在一起的代码抽离出来,同时以 use 前缀命名,声明一个自定义的 hook,如下:

10bet,App.vue根组件:

setup 本身的调用时机,从目前的源码来看,介于 beforeCreate 和 created 这两个生命周期之间,言外之意,就是你无法在这里使用 this 指向当前组件实例 对于 state 的声明,我们使用 reactive 这个 api 来构造,对于 computed state 的声明,使用 computed,两者本质上均是 Proxy 对象 对于组件方法的声明,我们直接通过声明普通函数的方式进行声明即可,对于 state 的变更,直接通过闭包使用 reactive 返回的 Proxy 对象即可 setup 的返回值被称作 render context,顾名思义,就是模板中可以访问到的各种数据和方法的上下文对象,我在之前的文章中曾提及,模板在解析数据时,会优先考虑从 data 对象取值,之后就是这个 render context 了 除了返回 render context,还可以返回模板渲染函数,对,就是那个 h,这种形式对应的情况是,当我们没有声明 template 属性时

3.1 执行时机

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

template div  h1App 根组件/h1 hr / LevelOne / /div/templatescriptimport LevelOne from './components/LevelOne'// 1. 按需导入 provideimport { provide } from '@vue/composition-api'export default { name: 'app', setup() { // 2. App 根组件作为父级组件,通过 provide 函数向子级组件共享数据(不限层级) // provide('要共享的数据名称', 被共享的数据) provide('globalColor', 'red') }, components: { LevelOne }}/script

每一个 vue2 中的组件生命周期函数,当前都对应一个生命周期 hook,比如:

template div !-- 4. 通过属性绑定,为标签设置字体颜色 -- h3 :Level One/h3 hr / LevelTwo / /div/templatescriptimport LevelTwo from './LevelTwo'// 1. 按需导入 injectimport { inject } from '@vue/composition-api'export default { setup() { // 2. 调用 inject 函数时,通过指定的数据名称,获取到父级共享的数据 const themeColor = inject('globalColor') // 3. 把接收到的共享数据 return 给 Template 使用 return { themeColor } }, components: { LevelTwo }}/script

这里值得注意的一点在于,对于 beforeCreate 和 created 生命周期,虽然有响应的 hook,但是我觉的没有必要单独使用了,因为这些逻辑代码大部分是一些初始化逻辑的代码,直接写在 setup 方法中即可。

在template中访问响应式数据:

这个 context 对象也是一个 Proxy 对象,当我们通过 context.attrs 访问其属性时,本质上代理对象会将访问指向组件的内部实例(即之间文章中提及的 componentInternalInstance)。

const count = ref(0)const name = ref('zs')watch( [count, name], // 需要被监视的多个 ref 数据源 ([count, name], [prevCount, prevName]) = { console.log(count) console.log(name) console.log('-------------') console.log(prevCount) console.log(prevName) }, { lazy: true })setTimeout(() = { count.value++ name.value = 'xiaomaolv'}, 1000)
import { ref } from "vue";export default {setup() { const count = ref { count.value++; } return { count, inc };}};

通过setup函数的第一个形参,接收props数据:

state

11.2 共享 ref 响应式数据

在这个基础上,复用代码的方式也不再像 vue2 中的那样,通过 mixin 或者 HOC 来达到复用代码的目的,这里稍微说一下,这些复用代码方式中比较显着的缺点有:

// 创建一个 ref 响应式数据const count = ref(1)// 创建一个 computed 计算属性const plusOne = computed({ // 取值函数 get: () = count.value + 1, // 赋值函数 set: val = { count.value = val - 1 }})// 为计算属性赋值的操作,会触发 set 函数plusOne.value = 9// 触发 set 函数后,count 的值会被更新console.log(count.value) // 输出 8

在 setup 那一小节中,我们知道,setup 在调用时,组件实例还未创建,那意味着我们无法使用 this 访问当前实例,那我想通过 this 在 vue2 中访问一些内置属性,怎么办?比如 attrs 或者 emit。我们可以通过 setup 的第二个参数:

在调用computed()函数期间,传入一个包含get和set函数的对象,可以得到一个可读可写的计算属性,示例代码如下:

setup { do anything...}
template p{{count}} --- {{name}}/p/template
interface PropTypesI { count: number}export default { setup { watch => { console.log(`count is: ` + props.count) }) }}

时间: 2019-09-09阅读: 98标签: vue30. 基础要求

引用类型

监视ref类型的数据源:

其代码结构看起来和 vue2 基本保持一致,不过有以下几点需要注意:

// 创建监视,并得到 停止函数const stop = watch(() = { /* ... */ })// 调用停止函数,清除对应的监视stop()
import useSearch from '@hooks/search'import useSort from '@hooks/sort'
setup(props) { console.log(props.p1)}

生命周期

【github -vuejs/composition-api】-api

这里使用 toRefs 的原因主要是因为,如果是 reactive 产生的对象,由于我们要只是保存对于该 Proxy 对象的引用,我们无法使用解构来将它 flat,而 toRefs 会将每一个属性在内部包裹为一个 ref 对象。

provide()和inject()可以实现嵌套组件之间的数据传递。这两个函数只能在setup()函数中使用。父级组件中使用provide()函数向下传递数据;子级组件中使用inject()获取上层传递过来的数据。

与 react hooks 对比

12.2 组件的引用

除了以 inline 的方式来声明,还可以将这些自定义的 hook 声明在单独的文件中,直接通过 import 导入即可,比如:

TemplateRefTwo.vue中的示例代码:

setup

页面上可以直接访问setup()中 return 出来的响应式数据:

  Count is: {{ state.count }}, double is: {{ state.double }} import { reactive, computed } from 'vue'export default { setup() { const state = reactive({ count: 0, double: computed => state.count * 2) }) function increment() { state.count++ } return { state, increment } }}

5.2 在 template 中访问 ref 创建的响应式数据

15 分钟掌握 vue-next 响应式原理vue-next/runtime-core 源码阅读指南

template div h5TemplateRefTwo --- {{count}}/h5 !-- 3. 点击按钮,让 count 值自增 +1 -- button @click="count+=1"+1/button /div/templatescriptimport { ref } from '@vue/composition-api'export default { setup() { // 1. 定义响应式的数据 const count = ref(0) // 2. 把响应式数据 return 给 Template 使用 return { count } }}/script

声明 state 主要有以下几种形式。

import { ref } from '@vue/composition-api'// 创建响应式数据对象 count,初始值为 0const count = ref(0)// 如果要访问 ref() 创建出来的响应式数据对象的值,必须通过 .value 属性才可以console.log(count.value) // 输出 0// 让 count 的值 +1count.value++// 再次打印 count 的值console.log(count.value) // 输出 1

vue-next 不依赖于其调用顺序,而 react 依赖 vue-next 提供了生命周期方法,而 react 刻意模糊生命周期的概念 vue-next 基于响应式系统实现,意味它的依赖不需要显示声明,而 react 需要手动声明依赖数组

watch 被重复执行了watch 被强制stop了

如何复用代码

  1. watch

对于 prop 可以通过如下代码声明及使用:

npm install @vue/composition-api --save# ORyarn add @vue/composition-api

写在前面

  1. setup

类似的东西在网上有很多,只是会比较零碎,同时有些也相对过时了,当然当前整理的这些也有可能会过时,毕竟代码还处于 pre-alpha 的阶段,但其中的设计思想应该是不会改变了。

import { onMounted, onUpdated, onUnmounted } from '@vue/composition-api'const MyComponent = { setup() { onMounted(() = { console.log('mounted!') }) onUpdated(() = { console.log('updated!') }) onUnmounted(() = { console.log('unmounted!') }) }}

这里可以发现其实和 vue2 中声明的方式基本一样,但值得注意的是,在 vue-next 中,props 的类型声明不是必须的,如果你使用 typescript,完全可以改写为如下的版本:

在使用任何@vue/composition-api提供的能力前,必须先通过Vue.use()进行安装

const count = ref(0)// 定义 watch,只要 count 值变化,就会触发 watch 回调// watch 会在创建时会自动调用一次watch(() = console.log(count.value))// 输出 0setTimeout(() = { count.value++ // 输出 1}, 1000)
import { createComponent } from 'vue'export default createComponent({ props: { foo: String }, setup(props) { props.foo // - type: string }})

示例代码如下:

Script 中的代码示例如下

// 定义数据源const state = reactive({ count: 0 })// 监视 state.count 这个数据节点的变化watch(() = state.count, (count, prevCount) = { /* ... */ })

在setup()函数中调用reactive()函数,创建响应式数据对象:

如下代码实现了点按钮切换主题颜色的功能,主要修改了App.vue组件中的代码,LevelOne.vue和LevelTwo.vue中的代码不受任何改变:

// 定义响应式数据 keywords const keywords = ref('')// 异步任务:打印用户输入的关键词const asyncPrint = val = { // 延时 1 秒后打印 return setTimeout(() = { console.log(val) }, 1000)}// 定义 watch 监听watch( keywords, (keywords, prevKeywords, onCleanup) = { // 执行异步任务,并得到关闭异步任务的 timerId const timerId = asyncPrint(keywords) // 如果 watch 监听被重复执行了,则会先清除上次未完成的异步任务 onCleanup(() = clearTimeout(timerId)) }, // watch 刚被创建的时候不执行 { lazy: true })// 把 template 中需要的数据 return 出去return { keywords}

按需导入reactive函数:

LevelTwo.vue组件:

安装插件后,您就可以使用新的Composition API来开发组件了。

import { ref } from '@vue/composition-api'setup() { const count = ref(0) return { count, name: ref('zs') }}

下面的列表,是 vue 2.x 的生命周期函数与新版 Composition API 之间的映射关系:

监视ref类型的数据源:

import Vue from 'vue'import VueCompositionApi from '@vue/composition-api'Vue.use(VueCompositionApi)
vue create my-project# ORvue ui

新版的生命周期函数,可以按需导入到组件中,且只能在setup()函数中使用,代码示例如下:

setup() { // 创建响应式数据对象 const state = reactive({count: 0}) // setup 函数中将响应式数据对象 return 出去,供 template 使用 return state}

toRefs()函数可以将reactive()创建出来的响应式对象,转换为普通的对象,只不过,这个对象上的每个属性节点,都是ref()类型的响应式数据,最常见的应用场景如下:

本文由10bet发布于Web前端,转载请注明出处:vue3.x 新特性 - CompositionAPI

关键词:

最火资讯