用 web components 实现带加载状态的按钮需联动 loading 属性与 ui 变化、交互禁用、视觉反馈:通过 observedattributes 监听属性变化,在 attributechangedcallback 中同步更新 shadow dom 状态,控制按钮禁用、加载指示器显隐及可访问性,并支持外部方法调用与事件派发。

用 Web Components 实现带加载状态的按钮,关键在于把 loading 属性 与 UI 变化、交互禁用、视觉反馈三者联动起来。它不是加个转圈图标就完事,而是要让组件在 loading 时真正“锁住”行为、同步状态、并保持样式隔离。
定义 loading 属性并响应变化
在自定义元素类中,通过 observedAttributes 声明监听 loading 属性,再在 attributeChangedCallback 中响应变更:
- 把
loading当作布尔属性处理(存在即 true,移除即 false) - 在回调里同步更新内部 Shadow DOM 的状态:切换按钮禁用态、插入/移除加载指示器
- 避免直接操作 light DOM,所有渲染逻辑收口到 Shadow DOM 内部
Shadow DOM 中控制按钮状态与视觉反馈
利用 Shadow DOM 天然的样式隔离能力,在模板中预置加载态结构,并通过 CSS 控制显隐:
- 按钮主体用
<slot></slot>接收文字或图标内容 - 加载指示器(如
<span class="spinner"></span>)默认隐藏,loading为 true 时显示 - 同时设置
button[disabled]或添加aria-busy="true",确保可访问性 - CSS 中用
.btn[loading] .spinner { display: inline-block; }控制切换,不依赖 JS 操作 class
集成轻量级加载动画(无需第三方库)
加载指示器本身也建议用 Web Components 封装(比如 <gaia-loading size="small"></gaia-loading>),但若追求极简,可直接内联 CSS 动画:
- 用
@keyframes spin定义旋转动画,配合border或clip-path实现紧凑 spinner - 尺寸适配按钮高度(例如
width: 16px; height: 16px;),避免撑开布局 - 动画仅在 loading 状态激活,其他时候完全不渲染,减少 DOM 节点开销
支持外部控制与事件一致性
按钮在 loading 状态下应拒绝点击,并在状态恢复后正确派发 click 事件:
- 在
click事件处理器中先判断this.hasAttribute('loading'),是则直接 return - loading 结束时(比如异步操作 resolve 后),主动移除
loading属性,并触发自定义事件如load-end - 对外暴露
startLoading()/stopLoading()方法,方便 JS 主动控制











