Skip to content

组合式 API (Composition Api)

Vue组件将组件和功能封装为按需重用的代码段,方便维护的同时,也增加了灵活性(个人理解是同一功能的差异部分可以切换不同组件或参数实现)。
但是,实际项目中,经常可以看到一个Vue组件动不动就几千行代码,还要小心地维持 options-api 的结构 ({ props, date, computed, methods, ... })。
组件相互间引用,一些重复的逻辑散落在各处,给维护带来了较大的难题。
需要尽量减少这种无序和重复、帮助我们共享或重用代码。

现在 可以 通过setup来使用 组合式 API (Composition Api) 以尝试让编码变得轻松一些

@/pages/40-lrn/20-vue3/10-composition-api/components/InvaluableAI.vue

vue
<template>
    <div>{{ answer }}</div>
    <input
        v-model="question"
        @keyup.enter="ask"
        @dblclick="ask"
        placeholder="ask sth..."
        v-if="!loading"
        autofocus
    />
</template>

<script lang="ts">
import { defineComponent } from "vue"
import { useInvaluableAI } from "./invaluable-ai"

export default defineComponent({
    setup() { return { ...useInvaluableAI(), } }
})
</script>

@/pages/40-lrn/20-vue3/10-composition-api/components/invaluable-ai.ts

ts
// @ts-check

import { ref, reactive, computed, toRefs, nextTick } from "vue"

export function useInvaluableAI() {
    const loading = ref(false);
    const formState = reactive({
        question: '',
        answer: '',
    });

    const isResolvableQuestion = computed(() => /^(.*)([??=])$/.test(formState.question))

    let resolveQuestion = (q: string) => q.replace(/^(.*)([??=])$/, ($, $1, $2) => {
        if ($2 === '?') return $1 + '!';
        if ($2 === '') return $1 + '';
        if ($2 === '=') return '=' + $1;
        return $;
    });

    let fetchAnswer = (q: string) : Promise<{ question: string, answer: string; }> => {
        return new Promise((ok, ko) => {
            setTimeout(() => {
                if (isResolvableQuestion.value) {
                    return ok({ question: q, answer: resolveQuestion(q) });
                } else {
                    return ko(new Error(`unknown`));
                }
            }, parseInt(String(Math.random() * 3000)));
        });
    };

    let ask = async ($event) => {
        loading.value = true;
        let result = await (fetchAnswer(formState.question)).catch(err => {
            return { question: formState.question, answer: `err: ${err.message}` };
        });
        formState.answer = result.answer;

        nextTick(() => {
            loading.value = false;
            $event && $event.target && $event.target.tagName === 'INPUT' && $event.target.select();
        });
    }

    const { question, answer, } = toRefs(formState);


    return { question, answer, ask, loading };
}