Vue.js 3 - Composition API使用详解1(setup函数基本使用)
作者:hangge | 2026-04-24 08:57
在 Vue.js 2 中,我们使用 Options API 的方式编写组件。Options API 最大的特点就是在对应的属性中编写对应的功能模块,比如在 data 中定义数据,在 methods 中定义方法,在 computed 中定义计算属性,在 watch 中监听属性改变,以及在组件中定义生命周期函数等。但是,使用 Options API 这种方式编写代码会带来一些弊端:
- 代码逻辑会被拆分,在实现某一功能时,对应的代码逻辑会被拆分到各个属性中。
- 当组件变得更大、更复杂时,逻辑关注点的列表就会变长,同一个功能的逻辑会被拆分得非常分散。
- 对维护这些复杂组件的开发者来说,过于分散的逻辑代码难以阅读和理解。
Composition API(组合式 API)是 Vue 3 的核心特性之一。它可以让我们把逻辑按“功能”划分,而不是散落在 data、computed、watch、methods 等各个选项中,使得代码阅读和复用都变得更加自然。在 Vue.js 3 组件中,如果想要使用 CompositionAPI 这种方式来编写代码,需要在 setup 函数中编写或使用 <script setup> 语法糖。下面我们看看应该如何在 setup 函数中编写 Composition API。
一、setup 函数基本使用
1,setup 函数介绍
(1)setup 函数实际上是 Vue.js 3 组件的一个选项。不同于之前的 methods、computed、watch、 data 和生命周期等选项,setup 函数的功能非常强大,可以替代之前的大部分选项。setup 函数会在组件被创建之前、props 被解析之后执行,它是编写 Composition API 的入口。
(2)特别要注意一下 setup 函数中 this 指向的问题。 根据 Vue.js 3 官方文档中的描述,this 并没有指向当前组件实例。此外, 在调用 setup 函数之前,data、computed、methods 等都没有被解析。Vue.is3 框架也没有为 setup 函数绑定 this,因此无法在 setup 中获取 this。
2,setup 函数的参数 1:props
(1)setup 函数主要有两个参数:props 和 context。props 作为第一个参数,父组件传递过来的属性会被放到 props 对象中。因此,我们可以直接通过该参数获取父组件传递过来的属性。
(2)首先我们创建一个 SetupProps.vue 组件,代码如下:
- 首先,在 props 选项中定义字符串类型的 message 属性。
- 接着,在组件中添加 setup 函数,该函数接收一个 props 参数。
- 然后,在该函数中分别打印 props 和 props.message。
注意:setup 函数可以直接通过参数来接收 props 对象,不可以通过 this 获取,因为 setup 函数没有绑定 this。
<template>
<div class="setup-props" style="border:1px solid #ddd;margin:10px">
SetupProps组件
<h4>{{message}}</h4>
</div>
</template>
<script>
export default {
props: {
message: {
type: String,
required: true
}
},
/**参数一: props, 父组件传递过来属性*/
setup(props) {
console.log(props)
console.log(props.message)
}
}
</script>
(3)接着在在 App.vue 组件中使用 <setup-props> 组件时为其 message 属性传递数据。
<template>
<div class="app" style="border:1px solid #ddd;margin:4px">
App组件
<setup-props message="学习setup函数的参数"></setup-props>
</div>
</template>
<script>
import SetupProps from './SetupProps.vue';
export default {
components: {
SetupProps
}
}
</script>
(4)运行效果如下下图所示。可以看到,在 SetupProps.vue 组件中定义的 message 属性,既可以在模板中直接使用,也可以通过 setup 函数的 props 参数获取。需要注意的是, props 是一个 Proxy 对象。

3,setup 函数的参数 2:context
(1)setup 函数第二个参数是 context,该参数对象包含以下三个属性:
- attrs:所有非 prop 的属性(attribute)。
- slots:父组件传递过来的插槽(slot)。
- emit:组件内部发送事件时用到的 emit 函数(setup 中不能访问 this,因此不可使用 this.$emit)。
(2)我们新建一个 SetupContext.vue 组件,代码如下所示:
- 首先 setup 函数中添加第二个参数 context。
- 接着,在 setup 函数中分别打印 context 中的 attrs、slots 和 emit 三个属性。
<template>
<div class="setup-context" style="border:1px solid #ddd;margin:10px">
SetupContext组件
<h4>{{ message }}</h4>
</div>
</template>
<script>
export default {
props: {
message: {
type: String,
required: true
}
},
/**参数一: props, 父组件传递过来属性*/
/**参数二: context, Vue框架传递过来上下文*/
setup(props, context) {
console.log(props.message); // 所有prop的attribute
// 所有的非prop的attribute
console.log(context.attrs.id, context.attrs.class);
console.log(context.slots); // 父组件传递过来的插槽
console.log(context.emit); // 用来触发事件的emit
}
}
</script>
- 注意:context 对象支持解构,下面代码效果通上面是一样的:
<template>
<div class="setup-context" style="border:1px solid #ddd;margin:10px">
SetupContext组件
<h4>{{ message }}</h4>
</div>
</template>
<script>
export default {
props: {
message: {
type: String,
required: true
}
},
/**参数一: props, 父组件传递过来属性*/
/**参数二: context, Vue框架传递过来上下文(context 对象支持解构)*/
setup(props, { attrs, slots, emit }) {
console.log(props.message); // 所有prop的attribute
// 所有的非prop的attribute
console.log(attrs.id, attrs.class);
console.log(slots);
console.log(emit);
}
}
</script>
(3)修改 App.vue 组件,向 <setup-context> 组件传递 props 和非 props 属性。
<template>
<div class="app" style="border:1px solid #ddd;margin:4px">
App组件
<setup-context message="学习setup context参数" id="code" class="hangge"></setup-context>
</div>
</template>
<script>
import SetupContext from './SetupContext.vue';
export default {
components: {
SetupContext
}
}
</script>
(4)运行效果如下下图所示,可以正常获取和打印 attrs、slots 和 emit 属性。

4,setup 函数的返回值
(1)setup 函数不仅可以接收 props 和 context 参数,还可以像普通函数一样有返回值。具体而言,setup 函数可以返回一个对象类型的值,该值可以直接在模板(template)中使用。这意味着我们可以使用 setup 函数的返回值代替 data 选项的返回值。
(2)新建 SetupReturm.vue 组件,代码如下:
- setup 函数返回一个对象,该对象中包含一个 counter 变量和一个 increment 函数。这两个属性可以直接在模板中使用。我们可以将 counter 变量绑定到 <h4> 元素上,以显示当前计数。
- 同时,我们还可以将 increment 函数绑定到 <button> 元素的 click 事件上,以在单击按钮时增加计数器的值。
<template>
<div class="setup-return" style="border:1px solid #ddd;margin:10px">
SetupReturn组件
<h4>当前计数: {{counter}}</h4>
<button @click="increment">+1</button>
</div>
</template>
<script>
export default {
setup(props, context) {
// 局部变量
let counter = 100;
// 局部函数
const increment = () => {
counter++;
console.log(counter);
}
// 返回值( 返回的属性可以直接在template中使用 )
return {
counter:counter, // 返回一个内部变量
increment:increment // 返回一个方法/函数
}
}
}
</script>
(3)修改 App.vue 组件,代码如下所示:
<template>
<div class="app" style="border:1px solid #ddd;margin:4px">
App组件
<setup-return></setup-return>
</div>
</template>
<script>
import SetupReturn from './SetupReturn.vue';
export default {
components: {
SetupReturn
}
}
</script>
(4)运行效果如下,可以看到 counter 的值显示出来了,当单击“+1”按钮时,会回调 increment 函数来修改 counter 变量,但是页面的数值并未响应式刷新。因为 counter 是一个普通的变量,默认情况下, Vue.js 3 并不会跟踪它的变化,所以页面没有响应式刷新。
提示:我们可以使用 Vue.js 3 提供的响应式 API 实现响应式的 counter 变量,具体见下文。
全部评论(0)