Vue Composition API

Options API 的弊端
在 Vue2 中,编写组件的方式是 Options Api
- Options API 的一大特点就是在对应的属性中编写对应的功能模块
- 比如 data 定义数据、 methods 中定义方法、 computed 中定义计算属性、 watch 中监听属性改变,也包括生命周期钩子
这种代码有一个很大的弊端:
- 实现某一个功能时,这个功能对应的代码逻辑会被拆分到各个属性中
- 组件变得更大、更复杂时,逻辑关注点的列表就会增长,那么同一个功能的逻辑就会被拆分的很分散
- 组件的代码是难以阅读和理解的
Composition API 的思想就是: 将同一个逻辑关注点相关的代码收集在一起
认识 Composition API
Vue2 是面向对象编程,
Vue3 是函数式编程
所有的代码都写在 setup 函数
代码演示:
App.vue
<template> |
useCounter.vue
import { ref } from 'vue' |
setup 函数
参数
它主要有两个参数
- 第一个参数: props
- 第二个参数: context
props 就是父组件传递过来的属性会被放到 props 对象中,在 setup 中如果需要使用,那么就可以直接通过 props 参数获取
- 对于定义 props 的类型,还是和之前的规则是一样的,在 props 选项中定义
- 并且在 template 中依然是可以正常去使用 props 中的属性,比如 message
- 在 setup 函数中想要使用 props,那么不可以通过 this 去获取
- 因为 props 有直接作为参数传递到 setup 函数中,所以可以直接通过参数来使用
context,也可以称之为是 SetupContext,它里面包含三个属性
- attrs:所有的非 prop 的 attribute
- slots:父组件传递过来的插槽
- emit:当组件内部需要发出事件时会用到 emit
返回值
setup 既然是一个函数,那么它也可以有返回值
- 返回值可以在模板 template 中被使用
- 可以通过 setup 的返回值来替代 data 选项
- 可以返回一个执行函数来代替在 methods 中定义的方法

注意:
上面定义的变量 counter 并不是响应式的
默认情况下, Vue 并不会跟踪它的变化,来引起界面的响应式操作
响应式 API
reactive
想为在 setup 中定义的数据提供响应式的特性,那么可以使用 reactive 的函数
- 因为当使用 reactive 函数处理我们的数据之后,数据再次被使用时就会进行依赖收集
- 当数据发生改变时,所有收集到的依赖都是进行对应的响应式操作(比如更新界面)
- 事实上,编写的 data 选项,也是在内部交给了 reactive 函数将其编程响应式对象的
const state =reactive({ |
Ref
reactive API 对传入的类型是有限制的,它要求我们必须传入的是一个对象或者数组类型
- 如果我们传入一个基本数据类型(String、 Number、 Boolean)会报一个警告:
value cannote be made reactive: Hello World |
对于基础数据类型可以使用 ref
- ref 会返回一个可变的响应式对象,该对象作为一个响应式的引用维护着它内部的值,这就是 ref 名称的来源
- 它内部的值是在 ref 的 value 属性中被维护的
const message = ref("Hello World"); |
注意:
- 在模板中引入 ref 的值时, Vue 会自动帮助我们进行解包操作,所以我们并不需要在模板中通过 ref. value 的方式来使用
- 但是在 setup 函数内部,它依然是一个 ref 引用,所以对其进行操作时,我们依然需要使用 ref. value 的方式, 手动解包
computed
某些属性是依赖其他状态时,可以使用计算属性来处理
- Vue2 是在 Options API 中,使用 computed 选项来完成的
- Vue3 是在 Composition API 中,在 setup 函数中使用 computed 方法来编写一个计算属性
使用方式
- 方式一:接收一个 getter 函数,并为 getter 函数返回的值,返回一个不变的 ref 对象
- 方式二:接收一个具有 get 和 set 的对象,返回一个可变的(可读写) ref 对象
// 方式一: |
在 setup 中如何使用 ref 获取元素或者组件
- 只需要定义一个 ref 对象,绑定到元素或者组件的 ref 属性上即可

生命周期函数
setup 可以用来替代 data 、 methods 、 computed 等等这些选项,也可以替代生命周期钩子
- 可以使用直接导入的 onX 函数注册生命周期钩子
onMounted(()=>{ |

Provide 和 Inject
Composition API 也可以替代之前的 Provide 和 Inject 的选项
通过 provide 来提供数据
- provide 方法来定义每个 Property
- provide 可以传入两个参数
- name:提供的属性名称
- value:提供的属性值
let counter = 100 |
通过 inject 来注入需要的属性和对应的值
- 可以传入两个参数
- inject 的 property 的 name
- 默认值
const counter = inject("counter") |
为了增加 provide 值和 inject 值之间的响应性,还可以在 provide 值时使用 ref 和 reactive
let counter = ref(100) |
watch
在 Options API 中,可以通过 watch 选项来侦听 data 或者 props 的数据变化,当数据变化时执行某一些操作
在 Composition API 中,我们可以使用 watchEffect 和 watch 来完成响应式数据的侦听
- watchEffect: 用于自动收集响应式数据的依赖
- watch: 需要手动指定侦听的数据源
使用 watch
watch 的 API 完全等同于组件 watch 选项的 Property
- watch 需要侦听特定的数据源,并且执行其回调函数
- 默认情况下它是惰性的,只有当被侦听的源发生变化时才会执行回调
const name = ref("fredo") |
- 使用数组同时侦听多个源
const name = ref("fredo"); |
深层的侦听
依然需要设置 deep 为 true
- 也可以传入 immediate 立即执行
const info reactive({ |
watchEffect
当侦听到某些响应式数据变化时,希望执行某些操作,这个时候可以使用 watchEffect
如下案例:
- 首先, watchEffect 传入的函数会被立即执行一次,并且在执行的过程中会收集依赖
- 其次,只有收集的依赖发生变化时, watchEffect 传入的函数才会再次执行
const name = ref("fredo"); |
停止侦听
- 如果在发生某些情况下,希望停止侦听,这个时候可以获取 watchEffect 的返回值函数,调用该函数即可
- 比如在上面的案例中,age 达到 20 的时候就停止侦听
const stopWatch = watchEffect(() => { |
script setup
<script setup> 是在单文件组件 (SFC) 中使用组合式 API 的编译时语法糖,当同时使用 SFC 与组合式 API 时则推荐该语法
- 更少的样板内容,更简洁的代码
- 能够使用纯 Typescript 声明 prop 和抛出事件
- 更好的运行时性能
- 更好的 IDE 类型推断性能
<script setup> |
里面的代码会被编译成组件 setup () 函数的内容
- 这意味着与普通的 <script> 只在组件被首次引入的时候执行一次不同
- <script setup> 中的代码会在每次组件实例被创建的时候执行
当使用 <script setup> 的时候,任何在 <script setup> 声明的顶层的绑定 (包括变量,函数声明,以及 import 引入的内容) 都能在模板中直接使用
<script setup> |
导入的组件直接使用
- <script setup> 范围里的值也能被直接作为自定义组件的标签名使用
<script setup> |
使用 <script setup> 的组件是默认关闭的
- 通过模板 ref 或者 $parent 链获取到的组件的公开实例,不会暴露任何在 <script setup> 中声明的绑定
- 通过 defineExpose 编译器宏来显式指定在 <script setup> 组件中要暴露出去的 property

props 和 emits
为了在声明 props 和 emits 选项时获得完整的类型推断支持,我们可以使用 defineProps 和 defineEmits API,它们将自动地在 <script setup> 中可用
<script setup> |
<template> |