- 前端
- UI组件
【免费下载链接】rsuite
🧱 A suite of React components .
Rate 评分组件用于表达用户对内容的评价,在 rsuite 中除了常规可交互状态外,还提供了disabled(禁用)、readOnly(只读)与plaintext(纯文本)三种不可交互展示形态,分别适用于表单提交后锁定、详情页展示与表单回显等场景。本文以 rsuite 官方文档 disabled.md 中的演示片段为主线,结合 src/Rate 目录下的组件源码、样式与测试用例,逐一剖析三种状态在视觉、交互与底层实现上的差异,帮助你按需选用正确的状态配置。
一、三种不可交互状态的官方示例
官方文档的 disabled.md 用一个对比示例完整展示了 Disabled、ReadOnly、Plaintext 三种状态的用法,示例使用HStack/VStack布局并配合Text标签,统一通过defaultValue={2.5}与allowHalf展示半星效果:
import { Rate, HStack, Text, Divider, VStack } from 'rsuite'; const App = () => ( <VStack divider={<Divider />}> <HStack> <Text muted w={80}> Disabled </Text> <Rate disabled defaultValue={2.5} allowHalf /> </HStack> <HStack> <Text muted w={80}> ReadOnly </Text> <Rate readOnly defaultValue={2.5} allowHalf /> </HStack> <HStack> <Text muted w={80}> Plaintext </Text> <Rate plaintext defaultValue={2.5} allowHalf /> </HStack> </VStack> );三行配置各只对应一个布尔属性,即可获得三种完全不同的展示行为。下面分别从视觉表现、交互阻断方式和源码实现三个层面展开。
二、disabled:完全禁用评分
2.1 使用方式与视觉表现
disabled是最“彻底”的禁用状态。从 src/Rate/styles/index.scss 的样式可以看出,当组件根节点带有data-disabled="true"属性时:
- 光标变为禁用光标(
cursor: var(--rs-cursor-disabled)),同时组件整体透明度降为0.5; - 所有字符(星标)被设置
pointer-events: none,鼠标点击、悬停均不会触发任何事件。
2.2 源码级的交互阻断
在 src/Rate/Rate.tsx 中,disabled的影响体现在两处:
- 容器
<StyledBox>的tabIndex被强制设为-1,使整个评分区域从键盘 Tab 导航中移除,并同时写入data-disabled与data-readonly两个数据属性; - 每个
Character子节点同样传入disabled={disabled || readOnly}(src/Rate/Rate.tsx)。
而 src/Rate/Character.tsx 中的eventHandlers逻辑进一步说明:当disabled为true时,onClick、onKeyDown、onMouseMove三个事件处理器整体置为null,字符的tabIndex也变为-1,即从 DOM 层面彻底移除了事件绑定。
2.3 测试用例验证
src/Rate/test/Rate.spec.tsx 中有两条专门的用例验证禁用行为:
it('Should disabled,cant click', () => { const { container } = render(<Rate defaultValue={1} disabled />); userEvent.click(container.querySelectorAll('.rs-rate-character')[3]); expect(container.querySelectorAll('[data-status="full"]')).to.have.length(1); }); it('Should disabled,cant hover', () => { const { container } = render(<Rate defaultValue={1} disabled />); userEvent.hover(container.querySelectorAll('.rs-rate-character')[3]); expect(container.querySelectorAll('[data-status="full"]')).to.have.length(1); });点击或悬停第四颗星后,满星数量始终为 1,说明disabled状态下评分值不会发生任何变化。适用场景:评分提交后锁定(如已评价过的商品、问卷已提交),此时值通常是受控的value。
三、readOnly:只读但保留视觉强度
3.1 与 disabled 的差异
readOnly同样禁止交互,但与disabled有两点显著区别:
- 不做透明度降级:对比样式表可发现,
data-readonly="true"的规则仅为字符设置cursor: default与pointer-events: none(src/Rate/styles/index.scss),组件不会变灰,评分结果保持原有视觉强度,更适合在详情页、审核页中“醒目地”展示评分; - 从键盘可达性上保留焦点入口不同:容器本身仍由
tabIndex={disabled ? -1 : 0}控制,readOnly状态下容器可聚焦,但字符层的disabled={disabled || readOnly}同样会移除各字符的事件处理器(见 src/Rate/Character.tsx),因此实际无法通过键盘改变评分。
3.2 底层实现要点
在 src/Rate/Rate.tsx 中,readOnly与disabled一样会写入根节点的data-readonly数据属性,供样式表精准选择。需要特别说明:源码中并没有对readOnly单独执行“值保护”逻辑,交互阻断完全依赖样式层的pointer-events: none与字符层的事件移除。因此从代码结构看,readOnly更适合用于展示已有评分值的场景,搭配value受控使用最为稳妥。
四、plaintext:纯文本回显
4.1 完全脱离星标渲染
plaintext与前两者在渲染策略上完全不同——它不再渲染任何星标字符,而是直接输出纯文本。看 src/Rate/Rate.tsx 的早退分支:
if (plaintext) { return ( <Plaintext localeKey="notSelected" className={className}> {!isNil(value) ? `${value}/${max}` : null} </Plaintext> ); }当值为非空数字时渲染"2.5/5"这种当前值/最大值格式;当值为空(null/undefined)时,子节点为null,由 src/internals/Plaintext/Plaintext.tsx 读取localeKey对应的本地化文案作为占位符,默认显示 “Not selected”(未选择)。
4.2 测试用例验证
src/Rate/test/Rate.spec.tsx 中有两条对应用例:
it('Should render current value and max value', () => { render(<Rate value={1} max={5} plaintext />); expect(screen.getByTestId('content')).to.have.text('1/5'); }); it('Should render "Not selected" if value is empty', () => { render(<Rate value={null} max={5} plaintext />); expect(screen.getByTestId('content')).to.have.text('Not selected'); });适用场景:表单提交后的详情回显、打印视图、或需要把评分当作普通文本排版(例如放进表格单元格、邮件正文)时使用。注意此时allowHalf对文本输出没有意义,文本格式始终为数值形式的value/max。
五、三态对比速查
| 状态 | 属性 | 视觉表现 | 交互能力 | 输出形态 | 典型场景 |
|---|---|---|---|---|---|
| 禁用 | disabled | 半透明(opacity 0.5)、禁用光标 | 完全不可交互(事件移除 + pointer-events none + 移出 Tab 序) | 星标 | 已锁定/不可修改的评分 |
| 只读 | readOnly | 正常色彩、default 光标 | 不可点击、不可悬停,容器可聚焦 | 星标 | 详情页醒目展示评分 |
| 纯文本 | plaintext | 无星标,纯文本 | 无任何交互 | 2.5/5或 “Not selected” | 表单回显、打印、表格内展示 |
六、与清理(cleanable)的关系
容易混淆的一点是cleanable(默认true)。它不是独立状态,而是影响可交互状态下的“点击已选星标清除评分”行为。在 src/Rate/Rate.tsx 的handleChangeValue中,只有当cleanable && value === nextValue && getStarStates(value)[index] === starStates[index]时才把值重置为 0。
需要强调的是:cleanable只在非禁用、非只读时才有意义。当disabled或readOnly为真时,事件处理器已被移除(见第二节),清除逻辑根本不会被触发。测试用例 src/Rate/test/Rate.spec.tsx 也验证了cleanable={false}时重复点击无法清除半星。
七、配套属性与受控/非受控说明
这三种状态通常与以下属性搭配使用(完整表格见 docs/pages/components/rate/en-US/index.md):
| 属性 | 类型(默认值) | 说明 |
|---|---|---|
disabled | boolean(false) | 为 true 时无法进行任何交互 |
readOnly | boolean | 为 true 时无法进行交互,视觉不做降级 |
plaintext | boolean | 以纯文本value/max形式展示 |
value | number | 当前值(受控) |
defaultValue | number(0) | 默认值(非受控) |
allowHalf | boolean(false) | 是否支持半选,示例中的 2.5 即依赖此属性 |
max | number(5) | 最大分数,同时决定纯文本输出中的分母 |
cleanable | boolean(true) | 是否支持点击清除,仅在可交互时生效 |
onChange | (value, event) => void | 值变化回调(受控模式建议配合使用) |
关于受控与非受控:defaultValue是首次渲染的初始值,后续用户操作由组件内部状态维护;value则完全由外部驱动,配合onChange使用。在disabled/readOnly场景下,推荐使用value直接指定展示值,避免内部状态与外部数据不一致。
八、总结
- 需要整体弱化、明确不可用时用
disabled,它会让组件半透明并从事件与焦点系统中完全剥离; - 需要保持视觉强度、仅禁止修改时用
readOnly,适合详情页展示; - 需要把评分当作文本数据(表单回显、打印、表格)时用
plaintext,输出value/max格式; - 三种状态都可以安全地与
allowHalf、defaultValue/value、max等属性组合,官方示例 disabled.md 即展示了最典型的defaultValue={2.5} allowHalf组合。
如需深入阅读实现,可依次查看 src/Rate/Rate.tsx、src/Rate/Character.tsx、src/Rate/styles/index.scss 与 src/Rate/test/Rate.spec.tsx。
- 前端
- UI组件
【免费下载链接】rsuite
🧱 A suite of React components .
相关推荐
rsuite MultiCascader 禁用与只读状态完整指南:disabled / disabledItemValues / readOnly / plaintext 实战解析
rsuite MultiCascader 禁用与只读状态完整指南:disabled / disabledItemValues / readOnly / plai
前端UI组件rsuite Cascader 禁用与只读状态全解析:disabled、disabledItemValues、readOnly 与 plaintext 实战指南
rsuite Cascader 禁用与只读状态全解析:disabled、disabledItemValues、readOnly 与 plaintext 实战指南
前端UI组件rsuite CheckPicker 禁用与只读状态全解析:disabled、disabledItemValues、readOnly 与 plaintext 实战指南
rsuite CheckPicker 禁用与只读状态全解析:disabled、disabledItemValues、readOnly 与 plaintext 实
前端UI组件
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考