Vue 3.0 即将发布,我们已经可以尝试一些新版本中带来的新功能,比如 Composition-API 组合式 API。如果你了解过 React 的 Hooks,那么当你看到组合式 API 时一定不会感到陌生。组合式 API 受到了 React Hooks 很大的启发。

Vue 非常易于使用,并且有非常出色的 API,对于初学者来说配合官方文档很容易就可以理解 Vue 的语法。但在国内一些大型的项目可能不会首选 Vue 去开发,因为当组件越来越大的时候会变得很难维护,很难找到一个变量在哪被定义又是在哪被使用。Vue2 中也有一些解决方法,比如 mixin、HOC、作用域插槽等等,但是都不能非常完美的去解决这个问题。

说到 mixin,其实 mixin 非常简单,我们可以通过它来把一些公共的数据、方法等等进行抽离后合并到一个组件。但当项目中的 mixin 越来越多的时候你就会发现命名冲突的可能性会变得很大,某些状态和方法的来源恨不清晰。

组合式 API 可以很完美的解决这个问题。

# Demo1

可以使用 Vue-CLI 搭建一个 Vue3 的项目,也可以直接下载 @vue/composition-api 包来使用。

npm i @vue/composition-api

main.js 文件中 use 组合式 API:

import compositionApi from '@vue/composition-api';
Vue.use(compositionApi);

从一个计数器的小案例开始。新建一个 Count.vue
在这里插入图片描述

<template>
  <div class="count">
    <button @click="increment">Count is: , double is: </button>
  </div>
</template>
<script>
import { reactive, computed } from "@vue/composition-api";
export default {
  name: "Count",
  setup() {
    const state = reactive({
      count: 0,
      double: computed(() => state.count * 2)
    });
    const increment = () => state.count++;
    return {
      state,
      increment
    };
  }
};
</script>

在 vue3 中有一个新的方法 setup() 。data、computed 等属性都需要放到 setup 中,setup 返回的是一个对象,该对象包含在组件中应该可用的所有内容。

另外还使用了两个函数 ** reactive() computed() **。reactive 与 Vue 2 中的 Vue.observable 等效。computed () 是创建计算属性的另一种方式,除此之外与 2 没有区别。

然后可以在 App.vue 中导入 Count.vue

<template>
  <div id="app">
    <Count />
  </div>
</template>
<script>
import Count from "@/components/Count";
export default {
  name: "app",
  components: { Count }
};
</script>

这是一个很简单的 demo。

# Demo2

在这里插入图片描述

让我们来继续尝试做一些更好玩的事情。一个可以从随机狗狗网站 https://dog.ceo 中获取狗狗照片的功能。

创建一个 useApi 函数,他的状态有: dataapi_status ,还有一个 initFetch 功能。useApi 接收 url 和 options 两个参数。我们将使用它从 https://dog.ceo 提供的 API 中提取随机的狗狗照片。创建一个 Dog.vue 组件,并添加如下代码:

const useApi = (url, options = {}) => {
  const state = reactive({
    data: null,
    api_status: ""
  });
  const initFetch = async () => {
    try {
      // 更改 API 状态
      state.api_status = "FETCHING";
      // 发送请求
      const response = await fetch(url);
      // 格式化返回结果
      const data = await response.json();
      state.data = data.message;
      // 修改 API 状态
      state.api_status = "FETCHING_SUCCESS";
    } catch (error) {
      // 处理错误情况
      state.api_status = "FETCHING_ERROR";
    }
  }; 
  // 判断有没有 fetchImmediately 属性,并且不为空
  if (Object.prototype.hasOwnProperty.call(options, "fetchImmediately") && options.fetchImmediately) {
    initFetch();
  }
  
  return {
    ...toRefs(state),
    initFetch
  };
};

这里使用到了 toRefs() ,稍后会详细讲。
在 useApi 函数中,我们声明了 state 包括 data 和 api_status。此外,initFetch 功能是更新 api_status 和发送请求。

接下来,我们检查 options 对象是否具有 fetchImmediately 属性。它指示在创建组件时是否应初始化 API 调用。最后,我们返回一个响应式 state 和 initFetch 函数的对象 。我们没有直接返回 state,而是使用 toRefs 进行包装。使用 toRefs 包装每个值,可以让他们具有响应性。

export default {
  setup() {
    const { data, api_status, initFetch } = useApi(
      "https://dog.ceo/api/breeds/image/random",
      {
        fetchImmediately: true
      }
    );
    return {
      dogImage: data,
      api_status,
      fetchDog: initFetch
    };
  }
};

如前所述,我们可以从 useApi 中解构所需的属性而不会失去响应性。此外,从 setup 返回的对象已重命名了属性。最后加上模板:

<template>
  <div style="margin-top: 20px;">
    <div v-if="api_status === 'FETCHING'">Fetching</div>
    <div v-else-if="api_status === 'FETCHING_ERROR'">Error</div>
    <div v-else-if="api_status === 'FETCHING_SUCCESS'">
      <img :src="dogImage" style="display: block; max-width: 500px; height: auto; margin: 0 auto;" />
    </div>
    <div v-else>Oops, no dog found</div>
    <button style="margin-top: 20px;" @click.prevent="fetchDog">Fetch dog</button>
  </div>
</template>

这些模板 divs 取决于 api_status 来显示或隐藏。由于传递 fetchImmediately: true 给 useApi,因此会在初始化时发送一条请求,您可以通过单击 Fetch dog 按钮来再一次发起请求。

你可以在 Github 上下载完整 demo 代码。

更新于 阅读次数

请我喝[茶]~( ̄▽ ̄)~*

Mengke 微信支付

微信支付

Mengke 支付宝

支付宝