rate —— 評分
Ce contenu n’est pas encore disponible dans votre langue.
評分把「打分」變成了離散的星級選擇:使用者點亮星星而不是輸入數字。core/rate 管的是逐星填充檔位(全星/半星/空)、半星步進與浮點累積、以及 APG slider 語義——評分控制項在無障礙層面是滑桿,不是單選群組。
- 各端實作
LhRate:商品/服務評價、難度標注、滿意度調查。 - 值域為 1~N 的整數(或允許半星的 0.5 步進)的場景。
- 不該用它:需要精確小數或任意範圍的連續值(用
slider或input-number);唯讀展示且無互動需求時仍可用 rate,但應切到readonly態。
import { LH_RATE_MAX_DEFAULT, clampRate, stepRate, getStarFill, getRateAriaText, getRateClassNames, getRateAria,} from '@lh-ui/share/core/rate'import type { LhRateState } from '@lh-ui/share/core/rate'stepRate 在加減後做 Math.round(next * 10) / 10——這不是多餘,是浮點累積的防禦:0.5 步進在 JS 裡是 0.5 → 1.0 → 1.5 沒問題,但 0.1 + 0.2 !== 0.3 這類陷阱在其它步進值下會出現,統一保留一位小數把結果釘回乾淨的小數。getStarFill 的判定順序是 full → half → empty:先判整星,再判半星,保證 value=2.5 時第 3 顆是 half 而非 empty。
getRateAriaText 用 formatMessage 插值 {n},文案模板來自語言包(rate.ariaText),數值先做同樣的 round 再轉字串——aria 文案與視覺填充必須基於同一個規範化後的值。
| 函式 | 簽名 | 傳回 | 作用 |
|---|---|---|---|
clampRate |
(value: number | undefined, max: number) => number |
鉗制值 | 非數值歸 0,上限由 max |
stepRate |
(value, direction: 1 | -1, allowHalf, max) => number |
步進值 | 半星 0.5 步進,一位小數 |
getStarFill |
(value, index, allowHalf) => 'full' | 'half' | 'empty' |
填充檔位 | 第 index 顆星(1 起) |
getRateAriaText |
(value, template: string) => string |
aria 文案 | 插值 {n} 星 |
getRateClassNames |
(state: LhRateState & { readonly, disabled }) => string[] |
類別名 | 唯讀/停用修飾 |
getRateAria |
(options: { value, max, disabled?, ariaValueText? }) => LhAriaAttrs |
aria 屬性包 | slider 語義 |
export interface LhRateState { max: number value: number allowHalf: boolean}
export const LH_RATE_MAX_DEFAULT = 5getRateAria 輸出 slider 語義(不是 radiogroup):評分的值是連續可調的(尤其半星模式),APG 的 rating 模式常以 slider 實作。鍵盤互動按 slider 規約:←/→ 減/增一步。
getRateAria({ value: 4.5, max: 5 })// { role: 'slider', 'aria-valuenow': 4.5, 'aria-valuemin': 0, 'aria-valuemax': 5 }
getRateAria({ value: 0, max: 5, disabled: true, ariaValueText: '0 星' })// { role: 'slider', 'aria-valuenow': 0, 'aria-valuemin': 0, 'aria-valuemax': 5,// 'aria-disabled': true, 'aria-valuetext': '0 星' }aria-valuetext 優先於 valuenow 播報——螢幕閱讀器會唸「4 星半」而不是「4.5」。每顆星按鈕另需 aria-label(UI 層用 getRateAriaText(value, t('rate.ariaText')) 生成)。
import { getStarFill, stepRate, clampRate } from '@lh-ui/share/core/rate'
getStarFill(3.5, 3, true) // 'full'getStarFill(3.5, 4, true) // 'half'getStarFill(3.5, 4, false) // 'empty'(整星模式下 3.5 的第 4 顆是空)getStarFill(3.5, 5, true) // 'empty'stepRate(3, 1, true, 5) // 3.5stepRate(3.5, 1, true, 5) // 4stepRate(0, -1, true, 5) // 0(鉗制)clampRate(undefined, 5) // 0clampRate(9, 5) // 5<!-- Vue3 --><div :class="getRateClassNames({ max, value, allowHalf, readonly, disabled })"> <div class="lh-rate__star-list" v-bind="getRateAria({ value, max, disabled, ariaValueText: getRateAriaText(value, t('rate.ariaText')) })" tabindex="0" @keydown.left="onStep(-1)" @keydown.right="onStep(1)" > <button v-for="i in max" :key="i" type="button" class="lh-rate__star" :class="`lh-rate__star--${getStarFill(value, i, allowHalf)}`" @click="onSelect(i)" > <LhIcon :name="getStarFill(value, i, allowHalf) === 'empty' ? 'star' : 'star-fill'" /> </button> </div></div>// React:半星模式用 hover 態決定 value,移動端用點選整星// 步進:const next = stepRate(value, dir, allowHalf, max); onChange(clampRate(next, max))// uniapp:<view> 遍歷 max 顆星;非 h5 端 aria 支援有限,getRateAria 的 undefined 屬性會被忽略| 類別名 | 語義 |
|---|---|
.lh-rate |
基礎類 |
.lh-rate--readonly |
唯讀(隱藏 hover 高亮、停用指標) |
.lh-rate--disabled |
停用 |
.lh-rate__star-list |
星群組容器(tabindex 與鍵盤事件掛這裡) |
.lh-rate__star |
單顆星按鈕 |
.lh-rate__star--full / --half / --empty |
填充檔位(半星用半遮擋疊加) |
.lh-rate__text |
分數文案(如「3.5 分」) |
星色 --lh-warning-color(黃),空星 --lh-fill-color / --lh-border-color。
getStarFill的 index 從 1 起,遍歷用v-for="i in max"(含 max)而非v-for="i in max - 1"。- 半星與整星的一致性:
allowHalf改變後,stepRate與getStarFill必須傳同一個值,否則點選與鍵盤步進的檔位對不上。 - 唯讀態的語義:
readonly只切類別名(視覺停用互動),getRateAria不輸出aria-disabled——唯讀評分仍應被螢幕閱讀器識別為可理解的評分值(靠aria-valuetext),這與 disabled 有區別。 max的邊界:LH_RATE_MAX_DEFAULT是 5;UI 層允許改 max,但星過多(如 20)在窄螢幕會溢位,需自行換行。- value 為小數但 allowHalf 為 false:core 不驗證這個組合,
getStarFill會把 3.5 當作「3 顆 full + 第 4 顆 empty」——屬於呼叫方的設定錯誤,視覺上表現為截斷。
@lh-ui/share/core/rate → getStarFill( )(填好参数后点运行)Copyright © 2024-2026 FengMo WenXue