vue3中的SetupContext函数详解

200 阅读3分钟

vue3中的SetupContext函数详解

在 Vue 3 的 Composition API 中,setup 函数的第二个参数是 SetupContext,它提供了组件在 setup 阶段需要的上下文信息。以下是 SetupContext 的详细解析,并结合 <script setup> 语法说明其用法。

  1. SetupContext 的作用

SetupContext 是一个对象,包含以下核心属性和方法,用于在 setup 函数中访问组件的上下文信息:

属性/方法作用
attrs包含组件接收的非 props 属性(未在 props 中声明的属性)。
slots包含组件的插槽内容(如默认插槽、具名插槽)。
emit用于触发自定义事件(类似 Vue 2 的 $emit)。
expose用于显式暴露组件公共属性或方法(Vue 3.2+)。
  1. 在传统 setup 函数中的用法

在非 <script setup> 的写法中,SetupContext 直接作为 setup 的第二个参数传入:

export default {
  setup(props, context) {
    // 访问属性和方法
    console.log(context.attrs);  // 非 props 属性
    console.log(context.slots);  // 插槽内容
    context.emit('event');       // 触发事件
    context.expose({ ... });     // 暴露公共方法
  }
}
  1. <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>
  1. 关键区别与注意事项
特性传统 setup 函数<script setup> 语法
访问上下文通过 context 参数直接访问需使用 useAttrs/useSlots 等组合式函数
事件定义需在 emits 选项中声明使用 defineEmits 宏直接声明
暴露方法通过 context.expose()使用 defineExpose 宏
自动暴露默认不暴露任何内容默认暴露模板中使用的属性和方法
  1. 常见场景示例

场景 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