Vue3 组合式API初体验

目录

  • 一、背景
  • 二、什么是组合式API(Composition API )
  • 组合式API全景
  • 为什么要引入组合式API
    • `mixins` 的方式
    • 域插槽的方式
    • 组合式API的方式
    • 结论
  • 组合式API存在的问题
  • 组合式API 的 script setup 语法糖
    • 顶层的绑定会被暴露给模板
    • 使用 `this`
    • steup中的生命周期钩子(对比 `Options API`)
  • 扩展
    • vite项目实现vue3函数和组件库的自动按需导入
  • 项目地址
  • 参考文档

一、背景

Vue3.x 版本的出现带来了许多令人眼前一亮的新特性,其中组合式 API(Composition API),一组附加的、基于功能的 API 被作为一种新的逻辑复用和代码组织的方式提供给了开发者,提供更加灵活的组合组件逻辑能力。

二、什么是组合式API(Composition API )

  • 组合式 API:一组低侵入式的、函数式的 API,使得我们能够更灵活地「组合」组件的逻辑
  • 用一句通俗的话来说:composition API 其实是用于解决功能、数据和业务逻辑分散的问题,使项目更益于模块化开发以及后期维护

先看一段简单的代码:

<template>
  <h2>组合式APIh2>
  <el-button type="primary" @click="increment">
    Count is: {{ state.count }}, double is: {{ state.double }}
  el-button>
  <div style="display: block;margin-top: 50px;">
    <router-link to="/" style="margin-top: 50px">首页router-link>
  div>
template>

<script>
import {computed, reactive} from "vue"

export default {
  setup() {
    const state = reactive({
      count: 0,
      double: computed(() => state.count * 2)
    })

    function increment() {
      state.count++
    }

    return {
      state,
      increment
    }
  }
}
script>

我们先来看下这段代码发生了啥?

import {computed, reactive} from "vue";

Component API 是以函数的形式展示组件属性,所以第一步就是导入我们需要的函数。在我们的例子中,我们用 reactive 创建响应属性,用 computed 创建计算属性。

export default {
  setup() {
    // ...
    return {
      state,
      increment
    }
  }

还有一个 setup 函数, setup 函数是一个新的组件选项。作为在组件内使用 Composition API 的入口点,如果 setup 返回一个对象,则对象的属性将会被合并到组件模板的渲染上下文,我们就可以在模板里使用对应的属性和方法。

组合式API全景

组合式 API 的使用,官方参考文档和 API 文档有详细说明,这里不过多说明。为方便大家理解和把握,根据官方的 API 文档整理了全景图。
Vue3 组合式API初体验_第1张图片
Vue 组合式API 可以分为五大块:

  1. 数据响应(复杂对象):响应性基础API ,支持复杂对象 ObjectArray 的数据响应
  2. 数据响应(内部值):内部值指 JS内置的简单数据结构,包括 StringNumber
  3. computedwatch:基于响应式数据的数据计算与监听
  4. 生命周期:对原生命周期封装,例如:onMountedonBeforeMount
  5. 其他 API:重要支持性 API

为什么要引入组合式API

在 Vue2 中我们采用 Options API 来写上面的代码:

<template>
  <h2>Option APIh2>
  <el-button type="primary" @click="increment">
    Count is: {{ count }}, double is: {{ double }}
  el-button>
  <div style="display: block;margin-top: 50px;">
    <router-link to="/" style="margin-top: 50px">首页router-link>
  div>
template>

<script>
export default {
  data() {
    return {
      count: 0
    }
  },
  computed: {
    double() {
      return this.count * 2
    }
  },
  methods: {
    increment() {
      this.count++
    }
  }
}
script>

那在 Vue2 中如果我们要复用这个逻辑,我们可以通过诸如 mixins 或作用域插槽的模式达成。

mixins 的方式

<template>
  <h2>Option API Mixinsh2>
  <el-button type="primary" @click="increment">
    Count is: {{ count }}, double is: {{ double }}
  el-button>
  <div style="display: block;margin-top: 50px;">
    <router-link to="/" style="margin-top: 50px">首页router-link>
  div>
template>

<script>
import CounterMixin from '@/mixins/counter'
export default {
  mixins: [CounterMixin]
}
script>

mixins 存在的问题是:

  1. 渲染上下文中暴露的 property 来源不清晰。例如在阅读一个运用了多个 mixin 的组件代码时,很难看出某个 property 是从哪一个 mixin 中注入的。
  2. 命名空间冲突。mixin 之间的 property 和方法可能有冲突。

域插槽的方式

<template>
  <h2>Option API Sloth2>
  <Counter v-slot="{ count, double, increment }">
    <el-button type="primary" @click="increment">
      Count is: {{ count }}, double is: {{ double }}
    el-button>
  Counter>
  <div style="display: block;margin-top: 50px;">
    <router-link to="/" style="margin-top: 50px">首页router-link>
  div>
template>

<script>
import Counter from '@/components/Counter'
export default {
  components: {
    Counter
  }
}
script>

优点:有了scoped slots,我们就可以通过v-slot属性准确地知道我们可以访问哪些属性,这样就更容易理解代码了。
缺点:我们只能在模板中访问,而且只能在 Counter 组件作用域中使用。

组合式API的方式

useCounter.js

// 将这部分代码逻辑抽离出来
import {computed, reactive} from "vue"

export function useCounter() {
  const state = reactive({
    count: 0,
    double: computed(() => state.count * 2)
  });
  const increment = function() { state.count++ }

  return {
    state,
    increment
  }
}

CounterSetup.vue

<template>
  <h2>组合式API script setup 语法糖h2>
  <el-button type="primary" @click="increment">
    Count is: {{ state.count }}, double is: {{ state.double }}
  el-button>
  <div style="display: block;margin-top: 50px;">
    <router-link to="/" style="margin-top: 50px">首页router-link>
  div>
template>

<script setup>
import { useCounter } from '@/libs/useCounter'
const { state, increment } = useCounter()
script>

是不是更加优雅了,相比较而言:

  1. 暴露给模板的 property 来源十分清晰,因为它们都是被组合逻辑函数返回的值。
  2. 不存在命名空间冲突,可以通过解构任意命名
  3. 不再需要仅为逻辑复用而创建组件实例
  4. 仅依赖它的参数和 Vue 全局导出的 API,而不是依赖其微妙的 this 上下文

结论

除了方便逻辑提取与复用之外,Composition API 带给我们的实际上更多的是一种新的代码编写思维。

当要去理解一个组件时,我们更加关心的是“这个组件是要干什么” (即代码背后的意图) 而不是“这个组件用到了什么选项”。基于 Options API 撰写出来的代码自然采用了后者的表述方式,然而对前者的表述并不好。

Options API 选项的强行分离为展示背后的逻辑关注点设置了障碍。此外,在处理单个逻辑关注点时,我们必须不断地在选项代码块之间“跳转”,以找到与该关注点相关的部分。

比如上面的例子中,基于 Options API 的方式我们必须在 datacomputedmethods 三个选项中跳转,来完成这段逻辑。而通过 Composition API 的方式我们把相同逻辑关注点的代码并列在一起,形成了一个独立的逻辑函数。

组合式API存在的问题

当然 Composition API 的引入也存在一定的弊端。

组合式API 在代码组织方面提供了更多的灵活性,但它也需要开发人员更多地自我克制来 “正确地完成它”,组合式API 会让没有经验的新手编写出“面条代码”。

Options API 中实际上形成了一种强制的约定:

  • props 里面设置接收参数
  • data 里面设置变量
  • computed 里面设置计算属性
  • watch 里面设置监听属性
  • methods 里面设置事件方法

会发现 Options API 都约定了我们该在哪个位置做什么事,这在一定程度上也强制我们进行了代码分割。

现在用 Composition API,不再这么约定了,所以代码组织非常灵活,如果作为一个新手,或者不深入思考的码农,那么在逻辑越来越复杂的情况下,setup 代码量越来越多,同样 setup 里面的 return 越来越复杂,势必会落入“面条代码”地步。

组合式API 的 script setup 语法糖

就是vue3新出的一个语法糖,使用方法就是在 script 标签的后面加上一个 setup 修饰。

代码如下:

<template>
  <h2>组合式API script setup 语法糖h2>
  <el-button type="primary" @click="increment">
    Count is: {{ state.count }}, double is: {{ state.double }}
  el-button>
  <div style="display: block;margin-top: 50px;">
    <router-link to="/" style="margin-top: 50px">首页router-link>
  div>
template>

<script setup>
import { useCounter } from '@/libs/useCounter'
const { state, increment } = useCounter()
script>

优点:

  1. 自动注册组件
  2. 属性和方法无需返回
  3. 更简洁的代码
  4. 更好的运行时性能

顶层的绑定会被暴露给模板

当使用

你可能感兴趣的:(前端,vue,vite,vue3)