标准答案
- 二次封装不是把底层组件所有 API 原样再暴露一遍,而是把业务常用配置固化,把少数变化点设计成清晰 props。
- slots 适合保留内容扩展能力,例如表格列、自定义按钮、弹窗 footer、表单项提示。
- emits 要把底层事件转换成业务语义清楚的事件,必要时统一参数结构。
- attrs 可以透传底层组件支持但封装层不关心的属性;使用 inheritAttrs: false 时要明确绑定到哪个内部节点。
- 封装边界要避免过死和过透:过死无法满足业务变化,过透则失去封装价值。
题目解析
这道题重点是封装取舍,而不是背 props、slots、emits 的定义。
一个好的二次封装组件应该降低重复业务配置,同时保留必要的扩展点。
如果底层组件升级会影响内部 class、slot 名或事件参数,封装层要尽量把这种变化隔离在组件内部。
代码示例
下面展示了一个把 attrs 透传到底层输入组件、同时收敛业务事件的封装。
Vue
<script setup lang="ts">
defineOptions({
inheritAttrs: false
})
defineProps<{
label: string
modelValue: string
}>()
defineEmits<{
'update:modelValue': [value: string]
search: [keyword: string]
}>()
</script>
<template>
<label class="field">
<span>{{ label }}</span>
<BaseInput
v-bind="$attrs"
:model-value="modelValue"
@update:model-value="$emit('update:modelValue', $event)"
@keyup.enter="$emit('search', modelValue)"
/>
</label>
</template>常见误区
- 二次封装只套一层壳,底层组件所有 props 和事件仍然散落到业务页面。
- 完全不透传 attrs,导致业务页面遇到少量特殊配置只能改封装组件源码。
- 事件参数没有统一,父组件仍要理解底层组件库的细节。