封装 Vue 组件时 props 怎么设计才更灵活?

博主惠泽 阅读 18

我最近在封装一个通用的按钮组件,想让它既能支持普通点击,又能传入自定义图标和样式。但每次加新功能就得改 props 结构,感觉很僵硬。比如现在这样写:

props: {
  type: { type: String, default: 'primary' },
  icon: { type: String, default: '' },
  disabled: { type: Boolean, default: false }
}

如果后面要加 loading 状态或者 size 属性,是不是得不停往 props 里堆?有没有更优雅的方式,比如用对象传参或者组合式 API 来提升扩展性?

我来解答 赞 4 收藏
二维码
手机扫码查看
1 条解答
萌新.冠羽
你这问题我太熟了,当年我也这么干过,props 里堆得跟小山似的,改个需求都得重新 review 一遍,人都麻了。

核心问题不是 props 堆不堆,而是「哪些是组件内部逻辑,哪些是外部可控的配置」没分清。比如 loadingsize 这些,真得全塞进 props 吗?不一定。

我建议分三层来设计:

第一层:基础交互类,比如 disabledloading,这类状态是组件自己维护的,但需要外部控制,可以保留为 props。

第二层:视觉样式类,比如 typesizeicon,这类其实可以拆成 class + style + slots 来组合控制,比硬编码 props 灵活多了。

第三层:内容定制类,比如图标、默认插槽内容,直接用 slotv-slot,别硬塞成字符串。

举个具体例子,你这个按钮可以这样改:

props: {
disabled: Boolean,
loading: Boolean,
// type 改成 class 前缀,或者直接让用户传 class
// size 也一样,或者直接用 class 控制
}

然后模板里:
:class="[
'btn',
type && btn-${type},
size && btn-${size},
loading && 'btn-loading',
disabled && 'btn-disabled'
]"
:disabled="disabled || loading"





外部调用的时候:

提交


或者更狠点,连 typesize 都不走 props,直接让用户传 class


你还可以结合 useAttrs(Vue3)把没声明的 attrs 全透传下去,比如 titlearia-label 这些,也不用一个个声明 props。

最后说句实话,如果你发现某个 prop 每次传的值都是固定几个,比如 ['small', 'medium', 'large'],那确实该加个 props;但如果每次都是拼出来的 class 名或者自定义值,不如直接让用户传 class 或 style,省心。

调试看看你现在的 props 列表,哪些是组件必须知道的逻辑状态,哪些只是样式变量,拆开后你会轻松很多。
点赞
2026-02-25 23:03