在 Ant Design 中用 character 属性定制 Rate 评分图标:字母、数字、图标与中文
【免费下载链接】ant-designAn enterprise-class UI design language and React UI library项目地址: https://gitcode.com/GitHub_Trending/an/ant-design
Rate 组件默认以星形图标表达评分等级,但在问卷、表情评价、活动打分等场景中往往需要把“星星”替换为更有语义感的图形或文字。本文以 Ant Design 仓库中 character 官方演示 为线索,完整讲解character属性支持的全部取值形态(ReactNode、回调函数),并结合组件源码、样式 Token 与测试用例,说明自定义字符与半星、尺寸、Tooltip、键盘操作等能力如何协同工作,帮助你直接复用出可运行的评分场景。
演示要解决的问题:把默认星形换成“其他字符”
demo/character.md 的中文说明非常直白:
可以将星星替换为其他字符,比如字母,数字,字体图标甚至中文。
也就是说,Rate 的每一个评分单元并不局限于StarFilled图标,而是一个可完全自定义渲染内容的“字符槽”。把character属性从默认的星形图标换成任意内容,即可得到不同的评分外观,例如字母 A 作为评分刻度、中文“好/坏”作为评价文案、心形图标作为收藏评分等。
官方演示完整代码与逐行解读
character演示的可运行源码位于 components/rate/demo/character.tsx:
import React from 'react'; import { HeartOutlined } from '@ant-design/icons'; import { Flex, Rate } from 'antd'; const App: React.FC = () => ( <Flex vertical gap="medium"> <Rate character={<HeartOutlined />} allowHalf /> <Rate character="A" allowHalf style={{ fontSize: 36 }} /> <Rate character="好" allowHalf /> </Flex> ); export default App;这段代码用三条 Rate 实例展示了三类最常见的自定义字符:
character={<HeartOutlined />}:传入一个图标元素(@ant-design/icons的心形图标)。由于图标字体天然跟随父级font-size缩放,因此可以像文字一样参与半星裁切。character="A":传入字母字符串,配合style={{ fontSize: 36 }}放大字号,得到“36px 的 A 字评分条”。character="好":传入中文字符,直接得到中文语义的评分单元。
三条 Rate 都开启了allowHalf(半选),说明自定义字符与半星模式可以无缝组合——这一点与官方文档 API 表格中的allowHalf(默认false)一致。而整个示例用Flex vertical gap="medium"纵向排布,保证三个评分条之间有合理的间距。
character 属性的完整取值类型
官方 Rate API 文档 中character的类型定义如下:
| 属性 | 说明 | 类型 | 默认值 | 版本 |
|---|---|---|---|---|
| character | 自定义字符 | ReactNode \| (RateProps) => ReactNode | <StarFilled /> | function 写法自 4.4.0 起 |
由此可以确定两点核心事实:
- 默认值是
StarFilled(星形实心图标),这正是 index.tsx 中character = <StarFilled />解构默认值对应的内容; character除了接收普通 ReactNode,还支持回调函数写法(4.4.0 起引入),这正是另一则演示 character-function.md 的主题:“可以使用(RateProps) => ReactNode的方式自定义每一个字符”。
进阶:用函数按“第几个评分位”渲染不同字符
只传一个 ReactNode,会让所有评分位都长得一样;当希望“1~2 星是哭脸、3 星是面无表情、4~5 星是笑脸”这类逐位差异化时,就需要使用函数形式。仓库中配套的 components/rate/demo/character-function.tsx 给出了可直接复用的写法:
import React from 'react'; import { FrownOutlined, MehOutlined, SmileOutlined } from '@ant-design/icons'; import { Flex, Rate } from 'antd'; const customIcons: Record<number, React.ReactNode> = { 1: <FrownOutlined />, 2: <FrownOutlined />, 3: <MehOutlined />, 4: <SmileOutlined />, 5: <SmileOutlined />, }; const App: React.FC = () => ( <Flex gap="medium" vertical> <Rate defaultValue={2} character={({ index = 0 }) => index + 1} /> <Rate defaultValue={3} character={({ index = 0 }) => customIcons[index + 1]} /> </Flex> );这段代码演示了两个实用技巧:
- 数字评分:
character={({ index = 0 }) => index + 1}利用回调参数中的index(从 0 开始)渲染1、2、3、4、5,直接把 Rate 变成数字打分器; - 按位映射图标:
character={({ index = 0 }) => customIcons[index + 1]}通过index + 1作为 key 去取事先准备好的图标映射表,实现“低分哭脸、高分笑脸”的情感评分。
回调参数被解构时给了index = 0的默认值,这是为了保证在 index 未传入等边界情况下仍然安全,实际使用时建议同样保留这一默认值处理。
源码级原理:character 如何进入 RcRate 并兼容 Tooltip
从 components/rate/index.tsx 可以看到 Rate 是对@rc-component/rate(RcRate)的一层封装,character相关的处理逻辑集中在几处:
const { ... character = <StarFilled />, ... } = props; const characterRender: RcCharacterRender = (node, { index = 0 }) => { if (!tooltips) { return node; } const tooltipsItem = tooltips[index]; if (isPlainObject<TooltipProps>(tooltipsItem)) { return <Tooltip {...tooltipsItem}>{node}</Tooltip>; } return <Tooltip title={tooltipsItem}>{node}</Tooltip>; }; return ( <RcRate ref={ref} character={character} characterRender={characterRender} ... /> );这里包含两层重要设计:
- props 默认值合并:未显式传入
character时,默认使用<StarFilled />,因此 API 表格中“默认值<StarFilled />”是组件内部真实存在的兜底,而不是文档空谈。 characterRender与tooltips的组合:自定义字符在最终渲染前会经过characterRender包装——一旦通过tooltips提供了逐位提示文案(类型为TooltipProps[] | string[],见 API 文档),包装层就会根据当前位index取出对应项,并以Tooltip包裹该字符(当该项是纯对象时透传其 TooltipProps,否则视为title字符串)。也就是说:自定义字符并不会破坏逐位 Tooltip 提示能力,两者在封装层被解耦处理。
此外,RateProps声明继承了 RcRate 的完整属性集合(export interface RateProps extends RcRateProps),并额外补充tooltips、size、rootClassName等,因此character的类型即来自底层的character/characterRender两个通道。
为什么自定义字符也能支持半星:样式层的裁切机制
许多自定义字符场景都会搭配allowHalf,这背后依赖的是 Rate 的样式实现。查看 components/rate/style/index.ts 中genRateStarStyle的生成逻辑:
.ant-rate-star { // 每个评分位内部实际上叠放了 first/second 两层内容 &-first, &-second { color: token.starBg; } &-first { position: absolute; width: 50%; height: 100%; overflow: hidden; // 左侧 50% 的裁切窗口 opacity: 0; } &-half &-first, &-half &-second { opacity: 1; } &-half &-first, &-full &-second { color: inherit; } }结合样式可以推断其工作原理:每个评分单元会把同一字符渲染两遍,其中-first层被绝对定位在一个宽度 50% 的隐藏裁切窗口中;半星状态下两层同时显示,从而视觉上只点亮左半侧字符;全选时则由-full对应的右侧层呈现完整字符。因此只要自定义字符是正常渲染的文本/图标,就能被这套 50% 裁切与叠色机制接管——字符外观可替换,但“半颗星”的底层布局逻辑保持不变。这也是演示中“心形、字母、汉字 + allowHalf”均可正确半选的原因。
自定义字符的尺寸控制与组件 Token
Rate 组件的字号直接决定了字符的显示大小。在样式入口 components/rate/style/index.ts 中可以看到:
- 根元素
.ant-rate的fontSize取自token.starSize,并提供了三档尺寸:starSizeSM(small)、starSizeLG(large)与默认的starSize(medium),换算关系为controlHeight * 0.625一类的基础控件高度比例; size属性('small' | 'medium' | 'large',默认'medium',见 API 文档)在 index.tsx 中被映射为ant-rate-small/ant-rate-large的 CSS 类。
因此想要单独放大某个自定义字符,有两种已验证的做法:
- 跟随组件尺寸:直接使用
size="large",整条评分条的字符都会按starSizeLG放大; - 单独覆盖字号:仿照演示在 Rate 上写
style={{ fontSize: 36 }},内联样式会覆盖 Token 生成的默认字号,实现任意大小的字符展示。
若要做全局主题化定制,可参考 组件 Token 演示 中的思路,通过 ConfigProvider 覆盖以下由 style/index.ts 声明的 Component Token:
| Token | 说明 |
|---|---|
starColor | 星星/被选中字符颜色(默认取token.yellow6) |
starSize/starSizeSM/starSizeLG | 中/小/大档字号 |
starHoverScale | 悬浮时的缩放变换(默认scale(1.1)) |
starBg | 未选中部分的底色(默认token.colorFillContent) |
值得留意的是,该文件还展示了选中态、hover 放大与键盘焦点focus-visible描边样式都定义在字符的外层> div上,因此自定义字符同样会获得悬浮放大、键盘聚焦描边等无障碍反馈,而非只是“换了张皮”。
character 之外的配套属性一览
要让自定义字符的评分条完整可用,通常会与下列官方属性组合(均见 Rate API 文档,此处整理与字符评分最相关的一组):
| 属性 | 说明 | 默认值 |
|---|---|---|
allowHalf | 是否允许半选 | false |
count | 评分位总数 | 5 |
defaultValue | 非受控默认值 | 0 |
value | 受控当前值 | - |
disabled | 只读,无法交互 | false |
keyboard | 支持键盘操作(5.18.0 起) | true |
size | 尺寸 | 'medium' |
tooltips | 逐位自定义提示TooltipProps[] \| string[] | - |
onChange(value: number) | 选择回调 | - |
onHoverChange(value: number) | 鼠标悬停变化回调 | - |
onFocus/onBlur/onKeyDown | 焦点与按键回调 | - |
另外 Rate 实例还暴露blur()与focus()两个方法用于手动管理焦点。结合前文characterRender的实现可见:tooltips既可以是字符串数组(快捷提示文案),也可以是逐位独立的TooltipProps对象数组(可精细控制title、placement等),两条路径都会正确包在自定义字符外层。
测试验证:演示被完整纳入快照与扩展渲染
仓库的测试体系印证了character自定义字符是稳定的公开能力:
- components/rate/tests/demo.test.tsx.snap 中存在
renders components/rate/demo/character.tsx correctly与renders components/rate/demo/character-function.tsx correctly两组快照,说明每个 demo 都会被真实渲染并与快照比对,防止字符替换逻辑意外回归; - 扩展上下文测试 demo-extend.test.ts.snap 同样覆盖这两个 demo(
extend context correctly),验证其在 ConfigProvider 扩展上下文下仍可正常渲染; - components/rate/tests/index.test.tsx 通过
focusTest、mountTest、rtlTest等共享测试用例(见 tests/shared)对 Rate 做了挂载、焦点与 RTL 方向的基线校验,其中也包含对size类名(ant-rate-small/ant-rate-large)的断言。
快速上手建议
在实际项目中使用自定义字符时,可遵循以下已被演示与源码共同验证的组合方式:
- 整体替换:单值
character={<Icon />}或character="字",适合全量统一外观; - 逐位替换:
character={({ index }) => ...},适合按等级区分语义(数字 1~5、哭脸/笑脸等),记得对index做安全默认处理; - 搭配半星:
allowHalf与自定义字符无冲突,字符会被 50% 裁切层正确渲染; - 调整大小:优先用
size,需要精细控制时内联fontSize或走 ConfigProvider 覆盖starSize系列 Token; - 补充可访问性与提示:保持默认
keyboard开启以获得方向键与焦点描边反馈,需要逐位说明时传tooltips数组,其会由characterRender自动包装到每个自定义字符上。
【免费下载链接】ant-designAn enterprise-class UI design language and React UI library项目地址: https://gitcode.com/GitHub_Trending/an/ant-design
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考