Vue3

Composition API 入门指南

全面讲解 Vue 3 中 Composition API 的核心概念与实战技巧,帮助前端小白快速掌握新特性。

🎯 引言

学习了这篇文章后,你能理解 Vue 3 中 Composition API 的核心思想,掌握如何使用 setup()、ref、reactive 等新 API,清楚生命周期钩子的用法以及 computed 和 watch 的新写法,告别 Vue 2 中繁琐的 this 语法,用更灵活的方式构建组件逻辑。对于刚接触 Vue 3 的小伙伴来说,这将大大提升你的开发效率和代码可维护性。


✨ 为什么要有 Composition API?

Vue 2.x 用的是 Options API,也就是我们熟悉的 data、methods、computed、watch 这些选项写法。虽然简单直观,但在组件逻辑复杂时,会导致代码分散且难以维护。比如,一个组件中有多个功能模块,每个功能相关的代码却分布在 data、methods、computed 不同部分,难以一眼看出模块整体逻辑。

Composition API 诞生的目的就是为了解决这个问题。它让我们把相关逻辑放在一起,通过函数式的写法组织代码,提高复用性和代码的清晰度。

打个比方,Options API 就像把功能相关的代码,按类别分别放进(data、methods、computed)等不同的盒子里面,虽然会比较规范,但是不利于查找。而 Composition API 是把一个功能模块的相关代码放在一个盒子里,方便查找和维护。

⚙️ setup() 的使用场景与逻辑

setup() 是 Composition API 的入口函数,组件创建时会调用它。这里可以进行响应式数据的声明、函数的定义以及生命周期钩子的注册。setup() 返回的对象会暴露给模板使用。

一个简单的组件示例:

<template>
    <div>
        <p>计数:{{ count }}</p>
        <button @click="increment">加一</button>
    </div>
</template>

<script>
import { ref } from 'vue';

export default {
    setup() {
        const count = ref(0);

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

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

这里所有组件逻辑都写在 setup() 里,不再需要 data 或 methods。

setup() 是 Vue 3 组件逻辑的心脏,你可以把它看成是组件的“工厂”,返回的数据和方法就是组件的“产品”。

💡 ref 与 reactive 的区别与使用

这两者都是用来声明响应式数据,但场景和本质有区别。

  • ref 用来包装基本类型数据(字符串、数字、布尔),也可以包装对象,但访问时要通过 .value。
  • reactive 用来将一个对象变成响应式,直接操作属性即可,不需要 .value。

示例:

import { ref, reactive } from 'vue';

const count = ref(0); // 基础类型,访问 count.value
const state = reactive({ name: '张三', age: 18 }); // 对象类型,访问 state.name
如果你只想声明一个简单的数字或字符串,用 ref。如果是复杂对象,推荐用 reactive。

但是 reactive 不能直接包裹基本类型,比如:

const num = reactive(0); // 错误用法

🕰 生命周期钩子在 setup() 中的替代品(onMounted 等)

Vue 2 里我们用 created、mounted、updated 等生命周期选项。Composition API 把它们拆分成了独立的函数,比如 onMounted、onUpdated。

示例:

import { onMounted } from 'vue';

export default {
    setup() {
        onMounted(() => {
            console.log('组件挂载完成');
        });
    },
};

这样我们能在 setup() 内部灵活调用对应钩子,逻辑更集中。

注意生命周期钩子只能在 setup() 中调用,不能放在普通函数里。

🧮 computed 与 watch 的新用法

computed 和 watch 也属于响应式 API,但写法变化不大。

computed 用于声明计算属性:

import { ref, computed } from 'vue';

const firstName = ref('');
const lastName = ref('');

const fullName = computed(() => {
    return firstName.value + lastName.value;
});

watch 用于监听响应式数据变化,执行副作用:

import { ref, watch } from 'vue';

const count = ref(0);

watch(count, (newVal, oldVal) => {
    console.log(`count 从 ${oldVal} 变成了 ${newVal}`);
});
watch 还能监听多个响应式数据,也可以写深度监听,使用起来更灵活。

💭 替代 this 的思维方式

在 Vue 2 中,我们通过 this 访问组件数据和方法,写法简单但容易混淆作用域。

Composition API 中,setup() 内不存在 this,上下文被移除。我们直接通过变量名访问,避免了 this 指向问题。

这就要求我们改变思维:

  • 数据和方法都通过变量和函数直接操作,不用 this。
  • 组件状态由一堆响应式变量构成,像普通 JS 代码一样组织。
  • 模板中仍然使用变量名访问,但底层不再依赖 this。

例如:

export default {
    setup() {
        const count = ref(0);

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

        return { count, increment };
    },
};

没有了 this,我们的代码更像纯函数,易于测试和维护。

✨ script setup 语法糖

Vue3 推出了 # script setup 语法糖,简单来说,它是对传统 setup () 函数的一个极简化写法。它的优势主要体现在代码更简洁、减少模板和逻辑之间的样板代码,让开发体验更友好。

传统写法中,setup () 需要手动 return 所有模板中会用到的变量和函数,代码较为冗长,容易漏写。而 # script setup 让你无需显式 return,所有顶层声明都自动暴露给模板。

举个例子:

<template>
    <button @click="increment">Count: {{ count }}</button>
</template>

<script setup>
import { ref } from 'vue';

const count = ref(0);
function increment() {
    count.value++;
}
</script>

上面代码中没有 return,变量和方法直接可用,整体更清爽。能够提高开发效率。

📦 defineProps 和 defineEmits 的使用方式

script setup 提供了两个编译时的辅助函数:defineProps 和 defineEmits。

它们帮我们声明组件的 props 和 emits 类型,同时在代码中可以直接使用。

使用 defineProps

<template>
    <h1>{{ props.title }} - {{ props.count }}</h1>
</template>

<script setup>
const props = defineProps({
    title: String,
    count: {
        type: Number,
        default: 0,
    },
});
</script>

使用 defineEmits

<template>
    <button @click="handleChange">Change</button>
</template>

<script setup>
const emit = defineEmits(['change']);

function handleChange() {
    emit('change', 'value');
}
</script>

这里的 emit 就是发射事件的方法,可以传递事件名和参数。


🧾 小节总结

  • Composition API 让组件逻辑更集中,解决了 Options API 代码分散的问题。
  • setup() 是组件逻辑的集中地,里面用 ref、reactive 创建响应式数据。
  • 生命周期钩子变成了独立函数(onMounted 等),只能在 setup() 中使用。
  • computed 和 watch 的写法更灵活,支持更复杂的响应式场景。
  • Composition API 去掉了 this,改成变量和函数直接操作,代码更清晰易维护。

❓ 知识问答(Q&A)

Q:为什么 Composition API 要移除 this?

A:去掉 this 可以避免作用域混乱,代码更像普通 JS,便于理解和测试。

Q:ref 和 reactive 有什么主要区别?

A:ref 用于包装基本类型,访问时用 .value;reactive 用于包装对象,直接访问属性。

Q:生命周期钩子怎么在 setup() 中使用?

A:使用对应的钩子函数,比如 onMounted(() => {...}),只能在 setup() 内调用。


🧪 小练习

练习1

用 Composition API 写一个计数器组件,实现加减功能,并且在计数变化时打印日志。

<template>
    <div>
        <p>计数:{{ count }}</p>
        <button @click="decrement">减一</button>
        <button @click="increment">加一</button>
    </div>
</template>

<script setup>
import { ref, watch } from 'vue';

const count = ref(0);

// 请实现 decrement 和 increment 函数

// 监听 count 变化,打印日志
</script>

练习2

写一个组件,使用 reactive 定义一个用户对象,包含 name、age 两个属性,并用 computed 计算用户的信息描述。

<template>
    <div>
        <p>用户信息:{{ userInfo }}</p>
    </div>
</template>

<script setup>
import { reactive, computed } from 'vue';

const user = reactive({
    name: '李四',
    age: 20,
});

// 请定义 computed 属性 userInfo,格式如:李四,20岁
</script>

🎉 恭喜你已经掌握 Composition API 的核心技能啦!能够用 Vue 3 写出可维护性更高、逻辑更清晰的组件了!继续多练习,相信你会成为 Vue 3 高手!