vue3 组合式API使用第1篇-保证学得会

667 阅读6分钟

本文已参与「新人创作礼」活动,一起开启掘金创作之路

1. 了解组合式API

1.1 选项式API特点

讲解 vue3 的组合式 API 之前,先来看看传统的选项式 API 的特点

一个非常明显的优点就是学习成本较低,因为框架已经规定死了

  • 数据在 data 中
  • 自定义方法及事件处理函数在 methods 中
  • 计算属性在 computed 中
  • 侦听器在 watch 中
  • 钩子函数中可能还分布了一些初始化代码
  • 。。。。。。。。。。。

但是当组件中功能越来越多,逻辑越来越复杂时,选项式 API 的确定就爆露出来了,那就是一个功能点的相关代码太分散了

这种死板的按照数据特点进行划分的方法非常不适合大项目的开发

下面是一张经典的 vue2 代码组织图,这是一个大型组件的示例,其中逻辑关注点按颜色进行分组,这种碎片化使得理解和维护复杂组件变得困难。选项的分离掩盖了潜在的逻辑问题。此外,在处理单个逻辑关注点时,我们必须不断地“跳转”相关代码的选项块

image.png

1.2 组合式API诞生

够将同一个逻辑关注点相关代码收集在一起,也就是写到一个地方,不再分散到各个选项中,如同一个功能用到的

  • 数据:原来data中或者prop中的数据
  • 方法:原来 methods 中的方法
  • 计算属性和侦听器中代码
  • 钩子函数中的代码
  • 。。。。

这就需要很多新的语法特性的支持,如在这个集中的地方,如何创建原来 data 中的响应式数据,如何注册钩子函数,如何在这个地方注册计算属性和侦听器等

这也是我们接下来要学的

2. setup 函数

组合式 API 在 setup 中编写,换句话说,setup 是组合式 API 的入口

  • setup 选项在组件创建之前执行(在beforeCreate钩子函数不调用之前),所以无法在 setup 函数中使用 this 引用组件实例

  • setup 的调用发生在 data property、computed property 或 methods 被解析之前,所以它们无法在 setup 中被获取

  • setup 返回的所有内容都暴露给组件的其余部分 (计算属性、方法、生命周期钩子等等) 以及组件的模板

  • setup 函数接受两个参数

    • props:父组件传入的数据
    • context:一个普通 JavaScript 对象,暴露了其它可能在 setup 中有用的值

setup 函数在beforeCreate钩子函数之前执行

<template>
  <h1>hello</h1>
</template>

<script>
export default {
  name: 'App',
  setup() {
    console.log('setup函数执行')
  },
  beforeCreate() {
    console.log('beforeCreate钩子函数执行了')
  },
}
</script>

<style>
</style>

结果

setup函数执行
App.vue?91a0:12 beforeCreate钩子函数执行了

3.响应式变量

setup 函数中声明的变量默认不是响应式的,这与在 data 选项中声明的变量不同,不同类型的变量想要转换为响应式的,方法也不太相同

我们这里先聊聊简单数据类型

3.1 简单数据类型

setup 函数中声明的变量默认不是响应式的,这与在 data 选项中声明的变量不同

<template>
  <h1 @click="change">{{ msg }}</h1>
</template><script>
export default {
  name: 'App',
  setup() {
    const msg = 'hello' // msg 就是一个普通变量,在单击事件中也无法修改其值
    return { msg }
  },
  methods: {
    change() {
      this.msg = 'world'
    },
  },
}
</script><style>
</style>

在 devtools中其也是不可以修改状态

通过 ref 函数可以将简单数据类型的变量定义为响应式数据

image.png

① 从 vue 中引入 ref 函数

② 使用 ref 将变量 msg 的值包裹起来

③ 在 setup 函数之外,使用 this.msg 访问变量

④ 在模板中使用变量

3.2 change 方法写在哪里

上面将 change 方法写道 methods 中

按照 vue3 中组合式 API 的原则,相同的逻辑关注点应该组合在一起,而不是分散在不同的选项中

所以 msg 及更改其值的方法应该组合在 setup 中

image.png

  • 在 setup 中访问其中定义的变量,不要使用 this,但要使用变量.value 方式为其赋值
  • setup 函数中要返回 msg 变量和 change 函数,这样才可以在模板中及其他地方使用

4. 钩子函数

如果希望页面加载时就请求接口获取数据,就需要在钩子函数中编写代码

组合式 API 上的生命周期钩子与选项式 API 的名称相同,但前缀为 on:即 mounted 看起来会像 onMounte

这些函数接受一个回调,当钩子被组件调用时,该回调将被执行

  • setup 创建实例前
  • onBeforeMount 挂载DOM前
  • onMounted 挂载DOM后
  • onBeforeUpdate 更新组件前
  • onUpdated 更新组件后
  • onBeforeUnmount 卸载销毁前
  • onUnmounted 卸载销毁后

setup 函数中要使用钩子函数,首先需要从 vue 中导出需要的钩子函数

image.png

4. 侦听器

4.1 侦听器实现

在 setup 函数中使用侦听器

  • 从 vue 中导入 watch 函数
  • 侦听器中监听响应式数据

修改上面的案例,类型id 值来自于父组件,那么就需要获取 props 中传入的 类型id,然后侦听这个 id 值的变化,已动态的更新书记列表

父组件

<template>
  <div class="nav">
    <a
      href="#"
      @click.prevent="change(item.id)"
      v-for="item in categoryList"
      :key="item.id"
    >
      {{ item.title }}
    </a>
  </div>
  <book-list :categoryId="categoryId"></book-list>
</template><script>
import axios from 'axios'
import { ref, onMounted } from 'vue'
import BookList from './components/BookList.vue'
export default {
  name: 'App',
  setup() {
    const categoryId = ref(1)
    const categoryList = ref([])
    const getCategory = async () => {
      const res = await axios.get('http://127.0.0.1:3000/api/book/category')
      categoryList.value = res.data.data
    }
    onMounted(getCategory)
​
    // 单击类别切换小说列表
    const change = (id) => {
      categoryId.value = id
    }
    return {
      categoryList,
      change,
      categoryId,
    }
  },
  components: {
    BookList,
  },
}
</script><style scoped>
.nav a {
  margin: 10px 20px;
}
</style>>
​

子组件

image.png

4.2 toRefs 和 toRef

首先说 toRefs 函数,这个了解了,toRef 函数自然就清楚了

toRefs是函数,转换响应式对象中所有属性为单独响应式数据,对象成为普通对象,并且值是关联的,如何理解呢?

1、响应式对象中结构出来的属性不是响应式的

下面创建一个响应式对象

image.png

这里为什么使用 reactive 创建响应式对象,而不使用 ref 呢?

创建响应式对象的推荐方式为

  • 简单数据类型,使用 ref,如字符串、数字、布尔值等
  • 复杂数据类型,使用 reactive,如对象、数组

如果使用 ref 创建响应式对象,则下面结构代码应为

const {name,age}=obj.value

不如上面代码直观

从对象中结构出来的 name 和 age 两个属性都不是响应式的

image.png

2、使用 toRefs 函数将结构出来的属性都转换为响应式的

image.png

我们上面案例中的 props 自然也是一个响应式对象,但是从其中结构出来的 categoryId 不是响应式的,所以需要使用 toRefs 函数将其属性都转换为响应式的,就可以根据 categoryId 的变化切换书籍信息了

3、toRef 函数将响应式对象中的单个属性转换为响应式的

toRefs 函数用于将响应式对象中的所有属性都转换为响应式的,这对于 props 对象来说非常合适,毕竟这个对象中的所有属性一定都需要是响应式的

但某些情况,可能响应式对象中只有某一个属性需要转换为响应式的,就可以使用 toRef 函数

image.png

image.png