vue3中的SetupContext函数详解
在 Vue 3 的 Composition API 中,setup 函数的第二个参数是 SetupContext,它提供了组件在 setup 阶段需要的上下文信息。以下是 SetupContext 的详细解析,并结合 <script setup> 语法说明其用法。
SetupContext的作用
SetupContext 是一个对象,包含以下核心属性和方法,用于在 setup 函数中访问组件的上下文信息:
| 属性/方法 | 作用 |
|---|---|
| attrs | 包含组件接收的非 props 属性(未在 props 中声明的属性)。 |
| slots | 包含组件的插槽内容(如默认插槽、具名插槽)。 |
| emit | 用于触发自定义事件(类似 Vue 2 的 $emit)。 |
| expose | 用于显式暴露组件公共属性或方法(Vue 3.2+)。 |
- 在传统
setup函数中的用法
在非 <script setup> 的写法中,SetupContext 直接作为 setup 的第二个参数传入:
export default {
setup(props, context) {
// 访问属性和方法
console.log(context.attrs); // 非 props 属性
console.log(context.slots); // 插槽内容
context.emit('event'); // 触发事件
context.expose({ ... }); // 暴露公共方法
}
}
- 在
<script setup>语法中的替代方案
<script setup> 是 Vue 3 的语法糖,它简化了 setup 的写法,但需要借助组合式 API 或编译器宏来访问 SetupContext 的功能。
(1) attrs:非 props 属性
使用 useAttrs 组合式函数:
<script setup>
import { useAttrs } from 'vue';
const attrs = useAttrs();
console.log(attrs); // 输出非 props 属性
</script>
<template>
<div v-bind="attrs">绑定所有非 props 属性</div>
</template>
(2) slots:插槽内容
使用 useSlots 组合式函数:
<script setup>
import { useSlots } from 'vue';
const slots = useSlots();
const defaultSlot = slots.default?.(); // 默认插槽内容
const headerSlot = slots.header?.(); // 具名插槽 "header"
</script>
<template>
<slot name="header"></slot>
<slot></slot>
</template>
(3) emit:触发事件
使用 defineEmits 编译器宏:
<script setup>
// 1. 定义事件
const emit = defineEmits(['update', 'submit']);
// 2. 触发事件
const handleClick = () => {
emit('update', { value: 123 });
};
</script>
<template>
<button @click="handleClick">提交</button>
</template>
(4) expose:暴露公共方法
使用 defineExpose 编译器宏(Vue 3.2+):
<script setup>
// 1. 定义需要暴露的方法
const publicMethod = () => {
console.log('父组件可调用此方法');
};
// 2. 显式暴露
defineExpose({
publicMethod
});
</script>
- 关键区别与注意事项
| 特性 | 传统 setup 函数 | <script setup> 语法 |
|---|---|---|
| 访问上下文 | 通过 context 参数直接访问 | 需使用 useAttrs/useSlots 等组合式函数 |
| 事件定义 | 需在 emits 选项中声明 | 使用 defineEmits 宏直接声明 |
| 暴露方法 | 通过 context.expose() | 使用 defineExpose 宏 |
| 自动暴露 | 默认不暴露任何内容 | 默认暴露模板中使用的属性和方法 |
- 常见场景示例
场景 1:透传非 props 属性
<script setup>
import { useAttrs } from 'vue';
const attrs = useAttrs();
</script>
<template>
<!-- 将非 props 属性透传给子元素 -->
<input v-bind="attrs" />
</template>
场景 2:动态插槽内容
<script setup>
import { useSlots } from 'vue';
const slots = useSlots();
// 根据插槽是否存在渲染内容
const hasFooter = !!slots.footer;
</script>
<template>
<div>
<slot name="header"></slot>
<main>内容区</main>
<slot v-if="hasFooter" name="footer"></slot>
</div>
</template>
场景 3:父子组件通信
<!-- 子组件 -->
<script setup>
const emit = defineEmits(['update']);
const handleInput = (e) => {
emit('update', e.target.value);
};
</script>
<template>
<input @input="handleInput" />
</template>
<!-- 父组件 -->
<template>
<Child @update="(value) => console.log(value)" />
</template>
总结
-
SetupContext在传统setup函数中直接通过参数传递,而在<script setup>中需使用组合式函数(如useAttrs)或编译器宏(如defineEmits)替代。 -
最佳实践:
-
始终使用
defineEmits声明事件,提升代码可维护性。 -
通过
defineExpose显式控制组件暴露的内容,避免意外暴露内部状态。 -
使用
v-bind="attrs"透传非 props 属性,增强组件灵活性。
-
更多vue相关插件及后台管理模板可访问vue admin reference,代码详情请访问github