likes
comments
collection
share

2.组合式函数

作者站长头像
站长
· 阅读数 2

选项式 API

在 Vue 中引入组合式 API 之前,开发人员用选项式 API 来组织组件逻辑,其中包括响应式数据、生命周期方法、计算属性等。选项式 API 允许在特定选项中定义这些方面,如下所示:

<!-- Template -->

<script>
  export default {
    name: "MyComponent",
    props: {
      // props
    },
    data() {
      // data
    },
    computed: {
      // computed properties
    },
    watch: {
      // properties to watch
    },
    methods: {
      // methods
    },
    created() {
      // lifecyle methods like created
    },
    // ...
  };
</script>

<!-- Styles -->

虽然这种方法达到了其目的并且仍适用于 Vue 3,但随着组件变得越来越大、越来越复杂,管理和维护可能会变得困难。在特定选项中定义组件逻辑可能会增加阅读和理解代码的难度,尤其是在处理大量组件时。在这个场景中,提取和重用组件之间的通用逻辑也可能很困难。

让我们看一个 App 组件的简单示例,它包含两个独立的子组件 —— Count 和 Width 。

<template>
  <div class="App">
    <Count :count="count" :increment="increment" :decrement="decrement" />
    <div id="divider" />
    <Width :width="width" />
  </div>
</template>

<script>
  import Count from "./components/Count.vue";
  import Width from "./components/Width.vue";

  export default {
    name: "App",
    data() {
      return {
        count: 0,
        width: 0,
      };
    },
    mounted() {
      this.handleResize();
      window.addEventListener("resize", this.handleResize);
    },
    beforeUnmount() {
      window.removeEventListener("resize", this.handleResize);
    },
    methods: {
      increment() {
        this.count++;
      },
      decrement() {
        this.count--;
      },
      handleResize() {
        this.width = window.innerWidth;
      },
    },
    components: {
      Count,
      Width,
    },
  };
</script>

上面的代码片段表示一个名为 App 的 Vue 单文件组件 (SFC: single-file component)。

<template> 部分定义组件的模板标签。在本例中,它包含一个带有“App”类的 <div> 元素,该元素包裹了两个子组件: <Count> 和 <Width> 。这些子组件使用 Vue 的属性绑定语法( :count 、 :increment 、 :decrement 和 :width )传递某些属性值。

<script> 部分包含组件的 JavaScript 代码。首先从各自的文件中导入 Count 和 Width 组件。 export default 语句用于导出组件定义。在本组件的定义中,我们可以看到有如下部分:

  • data 方法返回一个包含组件初始数据属性的对象,其中 count 和 width 初始化为 0。
  • mounted() 生命周期钩子用于在组件挂载到 DOM 中后执行代码。在本例中,它调用了 handleResize() 方法,并监听窗口大小变动事件。
  • beforeUnmount() 生命周期钩子用于在组件卸载和销毁之前执行代码。在这里,它删除了窗口大小变动事件的监听。
  • methods 对象包含组件的方法。它定义了 increment() 、 decrement() 和 handleResize() 方法,这些方法根据某些事件或行为操作计数和宽度。

打开沙箱运行代码

当应用运行时,实时显示当前计数和窗口内部宽度。用户可以通过使用 <Count> 组件中的按钮增加和减少计数来与组件交互。

2.组合式函数

同样,每当调整窗口大小时,宽度数据就会自动更新。

2.组合式函数

App.vue 单文件组件的构造方式可以如下所示:

2.组合式函数

尽管这个组件体积很小,但它内部的逻辑已经交织在一起。有些部分专用于计数的功能,而其他部分则涉及窗口大小逻辑。随着组件规模的增长,在组件内组织和定位相关逻辑将变得更具挑战性。

为了应对这些挑战,Vue 团队在 Vue 3 中引入了组合式 API。

组合式 API

组合式 API 可以看作是提供代表 Vue 核心功能的独立函数的 API。这些函数主要在 setup() 选项中使用,此选项作为使用组合式 API 的入口。

<!-- Template -->

<script>
  export default {
    name: "MyComponent",
    setup() {
      // the setup function
    },
  };
</script>

<!-- Styles -->

setup() 函数将在创建组件之前以及组件的属性可用时执行。

通过组合式 API,我们可以导入独立功能来让我们在组件中使用 Vue 的核心功能。让我们使用组合式 API 语法重写前述的计数器和宽度示例。

<template>
  <div class="App">
    <Count :count="count" :increment="increment" :decrement="decrement" />
    <div id="divider" />
    <Width :width="width" />
  </div>
</template>

<script>
  import { ref, onMounted, onBeforeUnmount } from "vue";
  import Count from "./components/Count.vue";
  import Width from "./components/Width.vue";

  export default {
    name: "App",
    setup() {
      const count = ref(0);
      const width = ref(0);

      const increment = () => {
        count.value++;
      };

      const decrement = () => {
        count.value--;
      };

      const handleResize = () => {
        width.value = window.innerWidth;
      };

      onMounted(() => {
        handleResize();
        window.addEventListener("resize", handleResize);
      });

      onBeforeUnmount(() => {
        window.removeEventListener("resize", handleResize);
      });

      return {
        count,
        width,
        increment,
        decrement,
      };
    },
    components: {
      Count,
      Width,
    },
  };
</script>

组件的 <template> 保持不变,但在组件的 <script> 中,我们使用带有 setup() 函数的组合式 API。

在 setup() 函数中,我们:

  • 使用 ref() 函数定义 count 和 width 响应性变量 - 该函数接受单个原始类型值(例如字符串、数字等)并返回响应性/可变的对象。
  • 我们还定义了自定义函数 increment() 、 decrement() 和 handleResize() 。这些函数与我们在之前的选项式 API 示例中定义的方法类似。
  • 我们使用 onMounted() 生命周期函数来调用自定义的 handleResize() 函数,并在组件挂载时为 resize 事件添加事件监听。同样,我们在组件卸载之前使用 onBeforeUnmount() 生命周期函数删除 resize 事件的事件监听。
  • 然后返回 setup() 函数中定义的响应性变量和函数,以便在组件模板中访问它们。

打开沙箱运行代码

组合式函数

通过我们之前的代码示例,人们可能仍然想知道 setup() 函数如何为开发提供任何优势,因为它似乎只需要我们在单个函数中声明组件选项。

采用组合式 API 的巨大好处之一是能够提取和重用组件之间的共享逻辑。这是因为我们可以简单地声明我们自己的函数,使用 Vue 的全局可用组合函数,并且让我们的函数可以轻松地在多个组件中使用以实现相同的结果

让我们进一步研究之前的计数器和宽度示例——通过创建并封装可跨组件、重用的共享逻辑的组合式函数。

首先,我们创建一个名为 useCounter 的组合式函数,它封装了计数器功能并返回 count 的当前值、一个 increment() 方法和一个 decrement() 方法。

按照惯例,组合式函数名称以 “use” 关键字开头。

import { ref } from "vue";

export function useCounter(initialCount = 0) {
  const count = ref(initialCount);

  function increment() {
    count.value++;
  }

  function decrement() {
    count.value--;
  }

  return {
    count,
    increment,
    decrement,
  };
}

同样,我们可以创建一个名为 useWidth() 的组合式函数,它封装了应用的宽度功能。

import { ref, onMounted, onBeforeUnmount } from "vue";

export function useWidth() {
  const width = ref(0);

  function handleResize() {
    width.value = window.innerWidth;
  }

  onMounted(() => {
    handleResize();
    window.addEventListener("resize", handleResize);
  });

  onBeforeUnmount(() => {
    window.removeEventListener("resize", handleResize);
  });

  return {
    width,
  };
}

在我们的 App 组件中,我们现在可以使用可组合函数来实现相同的结果:

<template>
  <div class="App">
    <Count :count="count" :increment="increment" :decrement="decrement" />
    <div id="divider" />
    <Width :width="width" />
  </div>
</template>

<script>
  import Count from "./components/Count.vue";
  import Width from "./components/Width.vue";
  import { useCounter } from "./composables/useCounter";
  import { useWidth } from "./composables/useWidth";

  export default {
    name: "App",
    components: {
      Count,
      Width,
    },
    setup() {
      const { count, increment, decrement } = useCounter(0);
      const { width } = useWidth();

      return {
        count,
        increment,
        decrement,
        width,
      };
    },
  };
</script>

通过这些更改,我们的应用程序的功能将与以前相同,但更具有组合式的风味。

打开沙箱运行代码

通过在组合式 API 中使用组合式函数,我们能够将应用的上下文分解为更小的、可重用的部分,从而分隔逻辑。

让我们将刚刚所做的更改进行可视化处理,与最初的选项式 API 示例组件进行比较。

2.组合式函数

在 Vue 中使用组合式函数可以更轻松地将组件的逻辑分成几个更小的部分。现在,重用相同的状态逻辑变得很容易,因为我们不再局限于在选项式 API 中的特定选项内组织代码。

借助组合式函数,我们可以灵活地提取和重用跨组件的共享逻辑。这种关注点分离使我们能够专注于每个组合式函数中的特定功能,从而使我们的代码更加模块化和可维护。

通过将逻辑分解为更小的、可重用的部分,我们可以使用这些组合式函数来构建组件,将必要的功能组合在一起,而无需重复代码。这种方法提高了代码的可重用性,并降低了代码重复和不一致导致的风险。

此外,使用组合式 API 可以提高组件逻辑的可读性可理解性。每个组合式函数都封装了组件行为的特定方面,使其更容易推理和测试。随着代码变得更加结构化和组织化,它还允许团队成员之间更轻松地协作。

最后,使用组合式 API 构建 Vue 应用程序可以实现更好的类型推断。由于组合式 API 帮助我们使用变量和标准 JavaScript 函数处理组件逻辑,因此使用 TypeScript 等静态类型系统构建大型 Vue 应用程序变得更加容易!

实用资源

组合式函数 | Vue 文档

Vue 组合式函数集合 | Vue使用