插槽实现带Loading状态的按钮组需解耦内容与逻辑:默认插槽传正常内容,loading插槽自定义加载态;各按钮独立loading状态,通过事件通知父组件更新;禁用、宽度保持、过渡动画及无障碍访问缺一不可。

用插槽实现带 Loading 状态的按钮组,核心是把“按钮内容”和“加载态逻辑”解耦,让父组件控制展示什么、何时加载、如何禁用,而子组件只负责结构与状态切换。全局组件设计的关键在于可复用性、状态隔离、样式可控和边界处理。
插槽结构设计:默认插槽 + 加载插槽
按钮组组件应支持两种内容注入方式:
- 默认插槽:用于传入正常状态下的按钮内容(如文字、图标+文字);
- loading 插槽(具名):可选,用于自定义加载中显示的内容(如 Spin 图标、文字提示),不传则使用内置简易 loading 指示器。
示例模板片段:
状态管理:每个按钮独立 loading,避免全局锁死
按钮组不应强制所有按钮共用一个 loading 开关,而应允许按需控制单个按钮状态:
- 接收
buttons: Array作为 prop; - 内部不修改传入数组,而是通过事件通知父组件更新(如
@loading-change="onLoadingChange"),保持响应式与不可变原则; - 点击时只触发对应按钮的 loading 切换,其他按钮不受影响。
这样既支持批量操作(如全部置灰),也兼容单个异步提交(如“保存”、“删除”并存且各自 loading)。
样式与交互细节:兼顾体验与可定制性
加载态下按钮需视觉明确、操作安全:
-
禁用状态同步:
:disabled="btn.loading || btn.disabled",防止重复点击; -
宽度保持:加载图标默认 inline-block + 固定宽高,或继承按钮原始 width(用
min-width: inherit或 flex 布局撑开); -
过渡动画:给
.btn > *:first-child和.loading-indicator添加opacity和transform过渡,避免突兀切换; -
键盘可访问性:loading 状态下仍保留
tabindex="0",但 aria-disabled="true",屏幕阅读器可感知。
全局注册与类型提示:Vue 3 + TS 实践建议
作为全局组件发布时,注意以下工程细节:
- 组件导出为
defineComponent,配合withDefaults提供 props 默认值; - 暴露类型:定义
ButtonGroupButton接口,并在 props 中标注buttons: ButtonGroupButton[]; - 全局注册时命名清晰,如
AppButtonGroup,避免和 UI 库冲突; - 提供
install方法,支持自动按需导入(配合 unplugin-vue-components); - 插槽作用域属性(
:button,:index)在文档中标明,方便使用者解构使用。
不复杂但容易忽略——比如忘记对 loading 插槽做 v-if 判断导致空节点渲染,或未透传原生 button 属性(type、form、autofocus)影响表单行为。

















