Vue3 的新特性(二) —— Composition-Api

目录

前言

本篇文章将介绍Vue3中的新增杀器 —— Composition API : 一组低侵入式的、函数式的 API,它使我们能够更灵活地「组合」组件的逻辑。

Composition API 的灵感来自于 React Hooks ,是比 mixin 更强大的存在。它可以提高代码逻辑的可复用性,从而实现与模板的无关性;同时函数式的编程使代码的可压缩性更强。另外,把 Reactivity 模块独立开来,意味着 Vue3.0 的响应式模块可以与其他框架相组合。

composition-api的优越性.png

如上图,在较大组件的编写中, Composition-Api 可以把复杂组件的逻辑抽地更紧凑,而且可以将公共逻辑进行抽取。


setup() 函数

在学习 Composition-Api 之前,我们需要先了解一下 setup() 函数。 setup() 是 Vue3 中的新增内容。它为基于 Composition API 的新特性提供了统一的入口。

在Vue3中,定义 methodswatchcomputeddata数据 等都放在了 setup() 函数中

1. 执行时机

setup()函数会在created()生命周期之前执行。

setup执行时机.png

2. 接收props数据

setup() 函数的第一个参数是 props ,组件接收的 props 数据可以在 setup() 函数内访问到。

setup(props) {
    console.log(props.p1)
}

3. context上下文对象

contextsetup() 的第二个参数,它是一个上下文对象,可以通过 context 来访问Vue的实例 this

setup(props,context) {
    console.log(this)
    console.log(context)
}
setup的context参数.png

注意:在 setup() 函数中访问不到Vue的 this 实例


Composition-Api

一组低侵入式的、函数式的 API,使得我们能够更灵活地「组合」组件的逻辑。

1. reactive()

reactive() 函数接收一个普通的对象,返回出一个响应式对象。

在Vue2.x的版本中,我们只需要在 data() 中定义一个数据就能将它变为响应式数据,在 Vue3.0 中,需要用 reactive 函数或者 ref 来创建响应式数据。

  • 用reactive创建响应式对象

    // 在组件库中引入 reactive
    import { reactive } from '@vue/    composition-api'
    
    setup() {
        // 创建响应式对象
        const state = reactive({
            count:0
        });
    
        // 将响应式对象return出去,暴露给模板使用
        return state;
    }
    
  • 使用响应式对象

    <p>当前的count的值为:{{count}}</p>
    
    <button @click="count++">点击增加count<  button>
    

2. ref()

ref() 函数可以根据给定的来创建一个响应式的数据对象,返回值是一个对象,且只包含一个 .value 属性。

  • 用 ref 创建响应式对象

    // 引入 ref
    import { ref } from '@vue/composition-api'
    
    setup() {
        // 创建响应式对象
        const count = ref(0);
    
        return {
            count
        }
    }
    
  • 使用响应式对象

    <p>当前的count的值为:{{count}}</p>
    
    <button @click="count++">点击增加count</button>
    
  • ref 的注意事项

    1. setup() 函数内,由 ref() 创建的响应式数据返回的是对象,所以需要用 .value 来访问;

      而在 setup() 函数外部则不需要 .value ,直接访问即可。

    2. 可以在 reactive 对象中访问 ref() 函数创建的响应式数据。

    3. 新的 ref() 会覆盖旧的 ref()

  • 选择 reactive 还是 ref

    Vue3 —— 创建响应式数据使用 reactive 还是 ref ?(本周更新)

3. computed()

computed() 用来创建计算属性,返回值是一个 ref() 实例。按照惯例,使用前需要先引入。

  • computed创建只读计算属性

    computed() 传入一个函数,可以得到一个只读的计算属性:

    const count = ref(1)
    
    // 创建一个计算属性,使其值比 count 大 1
    const bigCount = computed(() => count.value + 1)
    
    console.log(bigCount.value) // 输出 2
    bigCount.value++ // error 不可写
    
  • computed创建可读可写计算属性

    const count = ref(1)
    
    // 创建一个 computed 计算属性,传入一个对象
    const bigCount = computed({
        // 取值函数
        get: () => (count.value + 1),
        // 赋值函数
        set: val => {
          count.value = val - 1
        }
    })
    
    // 给计算属性赋值的操作,会触发 set 函数
    bigCount.value = 9
    // 触发 set 函数后,count 的值会被更新
    console.log(count.value) // 8
    

4. readonly()

传入一个响应式对象、普通对象或 ref ,返回一个只读的对象代理。这个代理是深层次的,对象内部的数据也是只读的。

const state = reactive({ count: 0 })

const copy = readonly(state)

watchEffect(() => {
  // 依赖追踪
  console.log(copy.count)
})

// state 上的修改会触发 copy 上的侦听
state.count++

// 这里只读属性不能被修改
copy.count++ // warning!

5. watchEffect()

watchEffect() 会立即执行传入的函数,并响应式侦听其依赖,并在其依赖变更时重新运行该函数。

  • 基本用法

    const count = ref(0)
    
    // 初次直接执行,打印出 0
    watchEffect(() => console.log(count.value))
    
    setTimeout(() => {
      // 被侦听的数据发生变化,触发函数打印出 1
      count.value++
    }, 1000)
    
  • 停止侦听

    watchEffect() 使用时返回一个函数,当执行这个返回的函数时,就停止侦听。

    const stop = watchEffect(() => {
      /* ... */
    })
    
    // 停止侦听
    stop()
    
  • 更多功能

    请参照 composition-api 文档 —— watchEffect

6. watch()

composition-api 中的 watch 和 Vue2.x 中是一样的,watch 需要侦听数据,并执行它的侦听回调。默认情况下初次渲染不执行。

  • watchwatchEffect 的不同

    1. watch 初次渲染不执行
    2. watch 侦听的更具体
    3. watch 可以访问侦听数据变化前后的值
  • watch 侦听单个数据源

    侦听的数据可以是个 reactive 创建出的响应式数据(拥有返回值的 getter 函数),也可以是个 ref

    // 侦听一个 getter
    const state = reactive({ count: 0 })
    watch(
      () => state.count,
      (count, prevCount) => {
        /* ... */
      }
    )
    
    // 直接侦听一个 ref
    const count = ref(0)
    watch(count, (count, prevCount) => {
      /* ... */
    })
    
  • watch 侦听多个数据源

    在侦听多个数据源时,把参数以数组的形式给 watch

    watch([ref1, ref2], ([newRef1, newRef2],   [prevRef1, prevRef2]) => {
      /* ... */
    })
    
  • watchEffect 同样的更多功能

    请参照 composition-api 文档 —— watch

Composition-Api 依赖工具

下面介绍一下组合式API的依赖方法集:

1. isRef()

isRef() 顾名思义,是用来判断某个值是否为 ref() 创建出来的响应式的值。

当你需要展开某个可能为 ref() 创建的响应式的值的时候,会用到它:

import { isRef } from '@vue/composition-api'

const unwrapper = isRef(foo) ? foo.value : foo

2. toRefs()

toRefs() 可以将 reactive() 创建出来的响应式对象转换成内容为 ref 响应式的值的普通对象

在搞清楚 toRefs() 的用法之前,我们需要先了解一下用 reactive()ref() 创建出来的响应式对象的区别:

  1. reactive() 创建的响应式对象,整个对象是响应式的,而对象里的每一项都是普通的值。当你把它用展开运算符展开后,整个对象的普通值都不是响应式的;
  2. 而用 ref() 创建的响应式的值,本身就是响应式的,并不依赖于其他对象。

所以当你需要展开 reactive() 创建的响应式对象,又不想让他们失去响应式特点的时候,就需要用 toRefs() 将它进行转换:

import { toRefs } from '@vue/composition-api'

setup() {
    // 定义响应式数据对象
    const state = reactive({
        count: 0
    })

    // 定义简单的函数,使count每次+1
    const add = () => {
        state.count++
    }

    // 将setup函数的内容return出去,供外界使用
    return {
        // 将 state 展开导出,同时将其属性都转化为 ref 形式的响应式数据
        ...toRefs(state),
        add
    }
}
<template>
    <div>
        <p>当前的count值为:{{count}}</p>
        <button @click="add">点击+1</button>
    </div>
</template>

其他方法

请参照 composition-api 文档 —— 响应式系统工具集

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 211,948评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,371评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,490评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,521评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,627评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,842评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,997评论 3 408
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,741评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,203评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,534评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,673评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,339评论 4 330
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,955评论 3 313
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,770评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,000评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,394评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,562评论 2 349