Rating 评分

以星级打分或者展示评分。

值:4

'use client'

import { useState } from 'react'
import { Rating, Stack, Text } from '@hina-ui/react'

export default function Demo() {
  const [score, setScore] = useState(4)

  return (
    <Stack gap="sm" align="start">
      <Rating value={score} onValueChange={setScore} size="lg" aria-label="评分" />
      <Text tone="muted" size="sm">
        值:{score}
      </Text>
    </Stack>
  )
}
tsx

用法

import { Rating } from '@hina-ui/react'
ts

评分由一排星组成,点击某颗星即选中该分值,悬停时前面的星预览为实心。value / onValueChange 绑定分值,max 指定满分,默认为 5。不传 stars 时星数与 max 相同;传入 stars 可独立指定显示的星数。未声明的属性都会传给包裹各星的组元素,请用 aria-label 或者 aria-labelledby 命名。

值:0

'use client'

import { useState } from 'react'
import { Rating, Stack, Text } from '@hina-ui/react'

export default function Demo() {
  const [score, setScore] = useState(0)

  return (
    <Stack gap="sm" align="start">
      <Rating value={score} onValueChange={setScore} aria-label="评分" />
      <Text tone="muted" size="sm">
        值:{score}
      </Text>
    </Stack>
  )
}
tsx

示例

半星

step 设为 0.5 时每颗星分成左右两半,可以选出 2.5 这样的分值。

值:2.5

'use client'

import { useState } from 'react'
import { Rating, Stack, Text } from '@hina-ui/react'

export default function Demo() {
  const [score, setScore] = useState(2.5)

  return (
    <Stack gap="sm" align="start">
      <Rating value={score} onValueChange={setScore} step={0.5} aria-label="评分" />
      <Text tone="muted" size="sm">
        值:{score}
      </Text>
    </Stack>
  )
}
tsx

分制与星数

max 为满分,stars 为显示的星数。设置 max={10} stars={5} 时,每颗星代表 2 分,值 7 显示为 3.5 颗星。

step 仍以星为单位:默认 1 表示整星,此时每次选择相差 2 分;设为 0.5 后每次相差 1 分。value、onValueChange 收到的值和通过 name 提交的表单值始终使用实际分值。只读展示按比例填充,不受 step 限制。

7 / 10

8.6 / 10 · 只读

'use client'

import { useState } from 'react'
import { Inline, Rating, Stack, Text } from '@hina-ui/react'

export default function Demo() {
  const [score, setScore] = useState(7)

  return (
    <Stack gap="md" align="start">
      <Inline gap="sm">
        <Rating
          value={score}
          onValueChange={setScore}
          max={10}
          stars={5}
          step={0.5}
          aria-label="评分"
        />
        <Text tone="muted" size="sm">
          {score} / 10
        </Text>
      </Inline>
      <Inline gap="sm">
        <Rating value={8.6} max={10} stars={5} readonly />
        <Text tone="muted" size="sm">
          8.6 / 10 · 只读
        </Text>
      </Inline>
    </Stack>
  )
}
tsx

只读展示

readOnly 把评分渲染为只展示的图形,值可以是任意小数,星按比例填充,适合展示平均分。

4.3 分,共 128 人评分

import { Inline, Rating, Text } from '@hina-ui/react'

export default function Demo() {
  return (
    <Inline gap="sm">
      <Rating value={4.3} readonly />
      <Text tone="muted" size="sm">
        4.3 分,共 128 人评分
      </Text>
    </Inline>
  )
}
tsx

尺寸

size 有 sm、md、lg 三档。

import { Rating, Stack } from '@hina-ui/react'

export default function Demo() {
  return (
    <Stack align="start">
      <Rating value={3} size="sm" aria-label="小号" />
      <Rating value={3} size="md" aria-label="中号" />
      <Rating value={3} size="lg" aria-label="大号" />
    </Stack>
  )
}
tsx

状态

disabled 禁用整组;clearable 默认开启,再次点击已选中的星会清零,关闭后不会。

'use client'

import { useState } from 'react'
import { Rating, Stack } from '@hina-ui/react'

export default function Demo() {
  const [fixed, setFixed] = useState(3)

  return (
    <Stack align="start">
      <Rating value={3} disabled aria-label="已禁用" />
      <Rating value={fixed} onValueChange={setFixed} clearable={false} aria-label="不可清零" />
    </Stack>
  )
}
tsx

在表单中

放进 FormField 后,标签通过 aria-labelledby 关联到整组星,错误信息由字段渲染;校验规则与提交交给 Form。未打分时值是 0。

'use client'

import { useState } from 'react'
import * as v from 'valibot'
import { Button, Form, FormField, Rating, Text } from '@hina-ui/react'

const schema = v.object({
  score: v.pipe(v.number(), v.minValue(1, '请先打分')),
})

export default function Demo() {
  const [values, setValues] = useState({ score: 0 })
  const [saved, setSaved] = useState('')

  async function save(data: unknown) {
    await new Promise(resolve => setTimeout(resolve, 600))
    setSaved(JSON.stringify(data))
  }

  return (
    <Form values={values} rules={schema} className="w-80" onSubmit={save}>
      {({ submitting }) => (
        <>
          <FormField name="score" label="评分" required>
            <Rating value={values.score} onValueChange={score => setValues({ ...values, score })} />
          </FormField>
          <Button type="submit" loading={submitting} className="self-start">
            提交评价
          </Button>
          {saved && (
            <Text tone="muted" size="sm">
              已提交:{saved}
            </Text>
          )}
        </>
      )}
    </Form>
  )
}
tsx

行为

  • 点击一颗星即选中该分值,再次点击同一颗星清零;悬停时前面的星预览为实心,移开后恢复。
  • 焦点落在某颗星上时,左右方向键移动焦点并选中,与单选框组相同。
  • 星的颜色变化有过渡。

无障碍

  • 可交互时整组是 role="radiogroup",每颗星或者每半颗星是带本地化名称的 role="radio"。
  • 只读时整组是 role="img",名称是语言包给出的「n 星,满分 m 星」。星数与满分不同时,单选项与只读图形的名称使用实际分值,如「7 分,满分 10 分」。
  • 通过 aria-label 或者 aria-labelledby 为整组命名。

API

Props

属性
类型
默认值
说明
value
number
0
分值
max
number
5
满分,须大于 0;未指定 stars 时也决定星数
stars
number
max
显示的星数,须为正整数
step
1 | 0.5
1
以星为单位的步长;实际分值步长为 max / stars * step
clearable
boolean
true
再次点击已选中的星是否清零
readOnly
boolean
false
是否只展示
name
string
—
表单字段名
size
'sm' | 'md' | 'lg'
'md'
尺寸
disabled
boolean
false
是否禁用
className
string
—
追加至根元素的类名

回调

回调
参数
说明
onValueChange
value: number
分值变化