应使用原生 <button> 元素实现 Vue 按钮组件,确保语义正确、键盘可操作(Enter/Space 触发)、禁用逻辑内置及屏幕阅读器支持;需提供清晰状态反馈(聚焦、悬停、激活、禁用、加载中),明确文案与 ARIA 补充,合理暴露 API 并保持职责单一。
设计一个既交互性强又符合无障碍标准的 Vue 按钮组件,核心在于兼顾视觉反馈、键盘可操作性、语义正确性和屏幕阅读器支持。不能只靠样式“看起来像按钮”,而要让按钮在任何使用方式下(鼠标、键盘、触控、辅助技术)都行为一致、表达清晰。
始终优先使用原生 <button> 标签,而非 <div> 或 <span> 加 click 事件模拟。Vue 中可直接绑定 props 和事件,无需额外 role 属性:
button 自动具备键盘焦点、Enter/Space 触发、禁用状态(disabled)语义和屏幕阅读器朗读能力<div @click="handleClick" role="button" tabindex="0"> —— 这会丢失表单提交行为、原生禁用逻辑,且需手动处理键盘事件(Enter/Space)role="button"、tabindex="0"、监听 @keyup.enter.prevent 和 @keyup.space.prevent
交互性强 ≠ 动效堆砌,而是让用户实时感知当前状态。重点覆盖:默认、悬停、聚焦、激活、禁用、加载中:
:focus-visible)必须有高对比度可见轮廓(如 outline: 2px solid #0066cc),不可仅依赖浏览器默认或设为 none
:hover)和激活(:active)应有明显样式变化(如背景加深、边框加粗),但避免仅靠颜色区分(需辅以图标、文字或形状变化):disabled 伪类控制样式,并确保 aria-disabled="true"(原生 button 已内置,无需手动加)loading prop 控制,替换文案(如显示“提交中…”)并禁用按钮,同时添加 aria-busy="true" 告知屏幕阅读器按钮的文本内容必须准确传达功能,避免“点击这里”“查看详情”等模糊表述:
立即学习“前端免费学习笔记(深入)”;
<span class="sr-only">关闭弹窗</span> 提供隐藏文本(CSS 中设 position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px; overflow: hidden; clip: rect(0, 0, 0, 0); white-space: nowrap; border: 0;)aria-label 或 aria-labelledby 补充上下文(例如按钮在卡片内,“编辑”需明确为“编辑用户张三”)组件应轻量、可控,不强制绑定复杂行为,把决策权留给使用者:
type(submit/button/reset)、disabled、loading、aria-label(用于图标按钮)、size、variant(primary/outline/text)@click,不封装防抖或 loading 状态管理 —— 这些应在业务层处理,保持组件职责单一icon 插槽,方便灵活组合;图标位置可通过插槽作用域或 prop 控制(如 icon-position="start")不复杂但容易忽略:可访问性不是加几个 ARIA 属性就完成的事,而是从语义结构出发,让每个交互环节对所有人透明、可预测、可控制。一个好按钮,鼠标用户能点,键盘用户能按,屏幕阅读器用户能听懂,还知道它现在能不能用。