标准答案

  1. 二次封装不是把底层组件所有 API 原样再暴露一遍,而是把业务常用配置固化,把少数变化点设计成清晰 props。
  2. slots 适合保留内容扩展能力,例如表格列、自定义按钮、弹窗 footer、表单项提示。
  3. emits 要把底层事件转换成业务语义清楚的事件,必要时统一参数结构。
  4. attrs 可以透传底层组件支持但封装层不关心的属性;使用 inheritAttrs: false 时要明确绑定到哪个内部节点。
  5. 封装边界要避免过死和过透:过死无法满足业务变化,过透则失去封装价值。

题目解析

这道题重点是封装取舍,而不是背 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,导致业务页面遇到少量特殊配置只能改封装组件源码。
  • 事件参数没有统一,父组件仍要理解底层组件库的细节。

作者信息