button —— 按钮
本頁內容尚未翻譯。
按钮是组件库里被改写次数最多的组件之一:类型、尺寸、形状、加载态、禁用态、块级宽度排列组合出大量变体。core/button 把这些变体的计算抽成纯函数——UI 层只管把 props 喂进来,把类名数组绑到根元素上。
- 各端实现
LhButton时:类名完全由getClassNames产出,UI 层不自己拼字符串。 - 需要在按钮外(如
LhDropdown的触发器、LhBackTop)复用同一套「类型 + 尺寸」语义时,直接调 core 函数而不是抄类名。 - 不该用它:表单提交逻辑、节流。core 只算「现在该长什么样」,不算「点了之后干嘛」。
import { isClickable, getSize, getClassNames } from '@lh-ui/share/core/button'import type { LhButtonState } from '@lh-ui/share/core/button'按钮的状态模型刻意做得很窄:LhButtonState 只含影响类名的字段。loading 与 disabled 都参与类名计算(--disabled),但「是否响应点击」是交互语义、不是视觉语义,所以单拆出 isClickable——加载中的按钮看起来正常但点不得,这个判定必须与类名计算独立,否则容易出现「类名加了 disabled 但事件没拦」的漏网。
尺寸走两级回退(组件 props → LH_SIZE_DEFAULT),但注意 getClassNames 内部对尺寸只吃 local size(第二参数传死 undefined):类名里的尺寸档不继承 ConfigProvider 全局尺寸,全局尺寸只作用于内联样式或下游自行决定。这是有意为之——类名是视觉契约,全局配置改的是「默认值」而非「覆盖」。
| 函数 | 签名 | 返回 | 作用 |
|---|---|---|---|
isClickable |
(state: { loading?: boolean; disabled?: boolean }) => boolean |
布尔 | loading 或 disabled 任一为真即 false,全缺省为 true |
getSize |
(localSize: string | undefined, globalSize: string | undefined) => string |
尺寸标识 | 两级回退,最终兜底 'medium' |
getClassNames |
(state: LhButtonState) => string[] |
类名数组 | 计算 lh-button 及全部修饰类 |
getStyle |
() => Record<string, string> |
{} |
主题变量占位,恒空(见下) |
getStyle 恒返回空对象值得说明:按钮的颜色完全由 :root 令牌(--lh-primary-* 等)驱动,ConfigProvider 的 themeVars 通过父级 CSS 变量级联到按钮,不需要在按钮元素上重复声明一遍。保留这个函数是为了与其它「可能有内联主题变量」的组件对称,调用方可以无脑 v-bind。
export interface LhButtonState { type: LhComponentType // 'primary' | 'success' | ... | 'default' size: LhComponentSize // 'mini' | 'small' | 'medium' | 'large' | 'x-large' loading: boolean disabled: boolean plain: boolean // 朴素:描边而非填充 block: boolean // 块级:占满父容器宽度 round: boolean // 圆角 circle: boolean // 正圆(通常配图标)}core/button 不输出 aria 属性包:按钮语义由 UI 层用原生 <button> 元素承载,disabled 直接走原生属性,读屏软件自然识别。这是「能用原生语义就不造轮子」原则的体现——只有原生表达不了的东西(spinbutton、treeitem、progressbar 这类)core 才提供 getXxxAria。
唯一需要 UI 层注意的:loading 态下按钮仍可被聚焦,但 isClickable 返回 false。此时应给按钮加 aria-busy="true",让读屏软件知道「操作在进行中」而不是「按钮坏了」。
import { getClassNames, isClickable } from '@lh-ui/share/core/button'
getClassNames({ type: 'primary', size: 'large', loading: false, disabled: false, plain: false, block: false, round: true, circle: false })// ['lh-button', 'lh-button--primary', 'lh-button--large', 'lh-button--round']
isClickable({ loading: true, disabled: false }) // falseisClickable({}) // true各端接线都是「props → state → 绑定」一个套路:
<!-- Vue3 --><button :class="getClassNames({ type, size, loading, disabled, plain, block, round, circle })" :disabled="disabled" :aria-busy="loading" @click="isClickable({ loading, disabled }) && emit('click', $event)"> <LhSpinner v-if="loading" :size="14" /> <slot /></button>// Reactconst cls = getClassNames({ type, size, loading, disabled, plain, block, round, circle })return <button className={cls.join(' ')} disabled={disabled} aria-busy={loading} onClick={onClick} />// uniapp:类名同样进 class 绑定;loading 图标用 LhSpinner(uniapp 端 svg 用图片兜底)styles/button/index.scss 的 BEM 结构:
| 类名 | 语义 |
|---|---|
.lh-button |
基础类:布局、字号、过渡 |
.lh-button--{primary|success|warning|danger|error|info|default} |
语义类型 |
.lh-button--{mini|small|medium|large|x-large} |
尺寸档(高度、padding、字号) |
.lh-button--plain |
朴素风格:透明底 + 描边 |
.lh-button--block |
块级宽度 |
.lh-button--round / .lh-button--circle |
圆角 / 正圆 |
.lh-button--disabled |
禁用态(指针、透明度) |
.lh-button--blank |
空白按钮(无边无底,hover 才显形) |
.lh-button__icon / .lh-button__text |
图标插槽与文字 |
.lh-button__loading / .lh-button__spinner / .lh-button__path |
加载图形 |
颜色全部走 var(--lh-primary-*) / var(--lh-success-*) 等令牌,暗色下由 var-dark.scss 自动翻转。
getClassNames的尺寸不继承全局配置(见「设计意图」),若你的端要求全局尺寸影响按钮,需在 UI 层先getSize(local, global)再传入。loading与disabled在类名上等价(都产出--disabled视觉),但交互判定走isClickable——不要用类名是否存在来推断可点击性。circle在样式中会强制正方形 + 正圆,给文字按钮加circle会得到奇怪的挤压。plain与type: 'default'组合接近不可见,这是朴素风格的预期表现。
@lh-ui/share/core/button → getClassNames( )(填好参数后点运行)Copyright © 2024-2026 风默文学 | 宁ICP备2024006574号 |
苏公网安备32040002010537