progress —— プログレスバー
プログレスバーは「ある作業がどこまで進んだか」を表します:アップロード、ダウンロード、インストール、審査。これは純粋な表示コンポーネントです——値がすべてを決定します。core/progress が管理するのは、パーセンテージのクランプ、状態の導出(満額で自動的に success)、円形プログレスの周長計算、そして APG progressbar のセマンティクスです。
- 各端末で
LhProgressを実装するケース:ファイルのアップロード進捗、タスクの実行進捗、読み込み時間の表示、容量の占有。 - 明確な「現在値 / 総量」の割合があるシーン。
- 使うべきでないケース:確定できない進行中の読み込み(
spinner/loadingを使う。これらは「どこまで」ではなく「動いている」ことを表します);ステップナビゲーション(stepsを使う)。
インポート方法
Section titled “インポート方法”import { clampPercent, resolveStatus, getProgressClassNames, getCircleCircumference, getProgressColor, formatPercentText, getProgressAria,} from '@lh-ui/share/core/progress'import type { LhProgressType, LhProgressStatus, LhProgressState } from '@lh-ui/share/core/progress'resolveStatus の自動導出:status がデフォルトの 'normal' のとき、value >= 100 なら自動的に 'success' になります。これは「設定より約束」です——満ちたことは成功したこと。ユーザーは毎回 :status="value >= 100 ? 'success' : 'normal'" と書く必要はありません。ただし明示的に指定された状態は上書きされません:warning を渡せば 100% でもずっと warning です。
clampPercent の NaN のゼロ化:NaN は伝播する代わりに 0 を返します。進捗値はしばしば非同期の計算から来ます(loaded / total、total が 0 のときは NaN)。ゼロ化により、UI はクラッシュや NaN% の表示ではなく「0%」を表示できます。
円の周長の計算:getCircleCircumference(width, strokeWidth) = 2π × (width - strokeWidth) / 2。これは SVG stroke-dasharray の標準的なアルゴリズムです:stroke-dasharray = 周长、stroke-dashoffset = 周长 × (1 - percent/100)。半径は先にストローク幅の半分を減らしてください。そうしないと円がキャンバスより一回り大きくなります。
getProgressColor の 3 段階の優先順位:ユーザーが渡した color(関数または文字列)> 状態に対応するトークン > デフォルトの主色。関数形式((percentage) => string)はグラデーションプログレスバー(例:0-50 は緑、50-80 は黄、80+ は赤)をサポートします。
| 関数 | シグネチャ | 戻り値 | 役割 |
|---|---|---|---|
clampPercent |
(value: number) => number |
[0,100] | NaN をゼロ化 |
resolveStatus |
(value, status) => LhProgressStatus |
状態 | normal かつ ≥100 → success |
getProgressClassNames |
(state: LhProgressState) => string[] |
クラス名 | タイプ / 状態 / テキスト |
getCircleCircumference |
(width, strokeWidth) => number |
周長 | SVG dash の計算 |
getProgressColor |
(status, color?, percentage?) => string |
色 | 3 段階の優先順位 |
formatPercentText |
(percentage) => string |
'50%' |
丸めテキスト |
getProgressAria |
(options: { percentage, label? }) => LhAriaAttrs |
aria 属性バッグ | progressbar セマンティクス |
export type LhProgressType = 'line' | 'circle'export type LhProgressStatus = 'normal' | 'success' | 'warning' | 'exception'
export interface LhProgressState { type: LhProgressType status: LhProgressStatus showText: boolean strokeWidth: number // line では高さ px、circle では SVG の stroke 幅 width: number // 円形キャンバスの幅 px}アクセシビリティ
Section titled “アクセシビリティ”getProgressAria({ percentage: 60, label: 'アップロード進捗' })// { role: 'progressbar', 'aria-valuenow': 60, 'aria-valuemin': 0, 'aria-valuemax': 100, 'aria-label': 'アップロード進捗' }
getProgressAria({ percentage: 100 })// { role: 'progressbar', 'aria-valuenow': 100, 'aria-valuemin': 0, 'aria-valuemax': 100 }role="progressbar"は APG の標準ロールです。スクリーンリーダーは「プログレスバー 60%」と読み上げます。aria-labelは可視テキストがない場合に必須:showText: falseのプログレスバーはスクリーンリーダーのユーザーには完全に見えません。到達可能な名前がなければなりません。可視テキストがある場合は省略できます(テキスト自体が名前になります)。- プログレスバーは
aria-readonlyです(デフォルトで暗黙)。追加で宣言する必要はありません。 - 動的プログレスの読み上げのスロットリング:毎秒何十回も更新されるプログレスバーでは、
aria-valuenowの頻繁な変化がスクリーンリーダーの読み上げを滞らせます。UI 層はaria-valuenowの更新頻度を毎秒 1 回程度まで下げるべきです(視覚的なアニメーションは影響を受けず、aria の更新頻度だけを下げます)。
import { clampPercent, resolveStatus, getProgressColor, getCircleCircumference } from '@lh-ui/share/core/progress'
clampPercent(50) // 50clampPercent(150) // 100clampPercent(-10) // 0clampPercent(NaN) // 0
resolveStatus(100, 'normal') // 'success'(満額で自動)resolveStatus(100, 'warning') // 'warning'(明示的な状態は上書きしない)resolveStatus(50, 'normal') // 'normal'
getProgressColor('normal') // 'var(--lh-primary-color)'getProgressColor('success') // 'var(--lh-success-color)'getProgressColor('warning') // 'var(--lh-warning-color)'getProgressColor('exception') // 'var(--lh-danger-color)'getProgressColor('normal', '#f00') // '#f00'(文字列を優先)getProgressColor('normal', (p) => p > 80 ? 'var(--lh-danger-color)' : 'var(--lh-success-color)', 90)// 'var(--lh-danger-color)'(関数が現在のパーセンテージに基づいて色を選ぶ)
getCircleCircumference(120, 8) // 2π × 56 ≈ 351.86formatPercentText(49.6) // '50%'(丸め)// グラデーション色の設定(関数の color)const color = (percentage: number) => percentage < 30 ? 'var(--lh-success-color)' : percentage < 70 ? 'var(--lh-warning-color)' : 'var(--lh-danger-color)'<!-- Vue3:ライン --><div :class="getProgressClassNames({ type: 'line', status, showText, strokeWidth, width })"> <div class="lh-progress__bar" role="progressbar" :aria-valuenow="clamped" aria-valuemin="0" aria-valuemax="100" :aria-label="showText ? undefined : label" > <div class="lh-progress__fill" :style="{ width: clamped + '%', height: strokeWidth + 'px', background: barColor }" /> </div> <span v-if="showText" class="lh-progress__text">{{ formatPercentText(clamped) }}</span></div><!-- Vue3:円形 --><div :class="getProgressClassNames({ type: 'circle', status, showText, strokeWidth, width })"> <svg :width="width" :height="width" :viewBox="`0 0 ${width} ${width}`"> <circle :cx="width / 2" :cy="width / 2" :r="(width - strokeWidth) / 2" :stroke-width="strokeWidth" fill="none" class="lh-progress__circle-track" /> <circle :cx="width / 2" :cy="width / 2" :r="(width - strokeWidth) / 2" :stroke-width="strokeWidth" fill="none" :stroke="barColor" stroke-linecap="round" :stroke-dasharray="circumference" :stroke-dashoffset="circumference * (1 - clamped / 100)" :transform="`rotate(-90 ${width / 2} ${width / 2})`" /> </svg> <span v-if="showText" class="lh-progress__circle-text">{{ formatPercentText(clamped) }}</span></div>const clamped = computed(() => clampPercent(props.percentage))const status = computed(() => resolveStatus(clamped.value, props.status))const barColor = computed(() => getProgressColor(status.value, props.color, clamped.value))const circumference = computed(() => getCircleCircumference(props.width, props.strokeWidth))// React:円形は stroke-dashoffset のアニメーション(CSS transition をこのプロパティに設定)// uniapp:ラインは <view> の幅パーセンテージ;円形は <canvas> か SVG(一部の端末ではサポートが限定)。// 簡易案は円形の代わりにラインのプログレスバーを使うことスタイルとトークン
Section titled “スタイルとトークン”| クラス名 | 意味 |
|---|---|
.lh-progress / --line / --circle |
基本クラス / タイプ |
.lh-progress--success / --warning / --exception |
状態(文字色 + 塗り色) |
.lh-progress--no-text |
テキストなし(右側のテキスト枠を除去) |
.lh-progress__bar |
トラック |
.lh-progress__fill |
塗り(幅のパーセンテージ) |
.lh-progress__text |
ラインのテキスト |
.lh-progress__circle-track |
円形のトラック |
.lh-progress__circle-text |
円形の中央テキスト |
トラック色 --lh-fill-color、塗りのデフォルト --lh-primary-color、状態色は --lh-success-color / --lh-warning-color / --lh-danger-color から取ります。
strokeWidthの 2 つの意味:line モードでは塗りの高さ(px)、circle モードでは SVG のストローク幅です。同じ prop に 2 つの意味があり、UI 層はtypeに応じて扱いを分けます。- 円形の
widthとstrokeWidthの関係:strokeWidthはwidthを超えてはなりません。超えると半径が負になり、周長が負の数になってstroke-dashoffsetの挙動が未定義になります。 showText: falseのときは必ずaria-labelを与えてください——これはアクセシビリティの必須要件で、オプションではありません。- アニメーションの境界:塗りの幅が 0 から 80% に跳ぶとき、CSS transition が補間します;しかし
clampedが NaN からゼロになる瞬間に一瞬ちらつく場合があります。UI 層は値が安定するまでレンダリングを控えられます。 resolveStatusと UI 層の状態連動:ビジネス上「100% でもまだ処理中」なら normal のままとしたい場合、status="normal"を明示的に渡しても自動的に上書きされてしまいます(自動導出は normal のときだけ発動し、normal → success は一方向のため)——この場合はexceptionやカスタム色で回避してください。- パーセンテージが 100 を超えるビジネス上の意味:
clampPercentはそのまま 100 にクランプします。「達成超過」(例:120%)を表現したいなら progress ではなくstatisticで数値を表示してください。 formatPercentTextの丸め:49.6は50%と表示され、精度が失われます。小数が必要なビジネスは自分でフォーマットしてください(core はパラメータを提供せず、関数を最小に保ちます)。
@lh-ui/share/core/progress → getProgressColor( )(填好参数后点运行)Copyright © 2024-2026 FengMo WenXue