ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

Handsontable React 星级评分单元格(Star Rating Cell)实战指南:基于 EditorComponent 的自定义编辑器与渲染器

Handsontable React 星级评分单元格(Star Rating Cell)实战指南:基于 EditorComponent 的自定义编辑器与渲染器 Handsontable React 星级评分单元格Star Rating Cell实战指南基于 EditorComponent 的自定义编辑器与渲染器【免费下载链接】handsontableJavaScript Data Grid / Data Table with a Spreadsheet Look Feel. Works with React, Angular, and Vue. Supported by the Handsontable team ⚡项目地址: https://gitcode.com/gh_mirrors/ha/handsontable本篇实战指南以 Handsontable 官方 React 封装handsontable/react-wrapper为基础手把手带你构建一个可在数据网格中直接点击选分的星级评分单元格编辑态显示可交互的星形选择器支持悬停预览、点击确认非编辑态通过自定义 React 渲染器显示只读星形数值以 1-5 数字形式存入单元格并可选配范围校验器。读完本文你将掌握 Handsontable 自定义单元格类型的完整链路——EditorComponentrender prop 用法、React 渲染器、validator 校验、CSS 变量主题适配以及按列定制星级数量等进阶能力。概览Overview本指南演示如何用 React 的EditorComponent构建一个星级评分编辑器单元格适用于商品评价、反馈表单等需要用户选择 1-5 星数值评级的场景。难度入门Beginner耗时约 15 分钟依赖库无需任何外部评分组件库星级 UI 由本地 React 组件实现你将构建什么What Youll Build一个具备以下能力的单元格编辑时显示可交互的星级评分器非编辑态通过自定义 React 渲染器展示星形支持选择前的悬停预览hover preview以数字1-5形式存储评分值校验评分范围例如 0-100提供点击即选click-to-select交互完全契合 React 组件化架构前置条件Prerequisitesnpm install handsontable handsontable/react-wrapper你需要具备React 16.8支持 Hookshandsontable/react-wrapper包基础 React 知识Hooks、JSX第 1 步导入依赖Import Dependenciesimport { HotTable, HotColumn, EditorComponent } from handsontable/react-wrapper; import { registerAllModules } from handsontable/registry; registerAllModules();导入内容说明EditorComponent—— 用于创建自定义编辑器的 React 组件HotTable/HotColumn—— React 封装后的表格与列组件registerAllModules()—— 注册 Handsontable 全部模块使用封装器时必需从仓库源码看这三个组件均从handsontable/react-wrapper的入口统一导出见 wrappers/react-wrapper/src/index.tsx而EditorComponent的实现位于 wrappers/react-wrapper/src/hotEditor.tsx。调用registerAllModules()是为了把内置编辑器、渲染器、插件一次性注册进 registry省去逐个注册的样板代码。第 2 步创建星级评分组件Star Rating Component创建一个本地组件渲染五颗星并向外部上报悬停与点击事件interface StarRatingProps { name: string; value: number; editing?: boolean; onStarHover?: (value: number) void; onStarClick?: (value: number) void; } function StarRating({ name, value, editing true, onStarHover, onStarClick }: StarRatingProps) { return ( div classNamestar-rating aria-label{Rating: ${value} out of 5} {[1, 2, 3, 4, 5].map((star) ( span key{${name}-${star}} className{star value ? star filled : star} onMouseEnter{editing ? () onStarHover?.(star) : undefined} onClick{editing ? () onStarClick?.(star) : undefined} ★ /span ))} /div ); }要点分析nameprop 为每颗星生成稳定的 React key例如rating-3避免复用组件时 key 冲突editingprop 在非编辑态下关闭悬停与点击事件处理直接传undefinedonStarHover在用户提交前预览目标分值onStarClick提交选中的分值第 3 步创建编辑器组件Editor Component使用EditorComponent的 render prop 模式封装编辑器 UIexport const RatingEditor () { return ( EditorComponentnumber {({ value, setValue, finishEditing }) ( div classNamerating-editor StarRating namerating value{Number(value) || 0} onStarHover{(nextValue) setValue(nextValue)} onStarClick{(nextValue) { setValue(nextValue); finishEditing(); }} / /div )} /EditorComponent ); };要点分析EditorComponent包裹编辑器 UIchildren是一个接收编辑器状态并返回 JSX 的函数render propvalue—— 当前单元格值数字评分setValue—— 更新值的函数finishEditing—— 保存并关闭编辑器的函数StarRating—— 渲染本地星形选择器onStarHover—— 用户悬停时更新预览onStarClick—— 保存所选评分并关闭编辑器rating-editordiv 位于 render prop 内部因此样式可作用于可见的编辑器区域关键概念Render prop 模式EditorComponent以函数作为 children由封装器注入编辑器状态悬停预览onStarHover让用户在提交前预览分值点击确认onStarClick保存并关闭编辑器源码级原理EditorComponent内部通过useHotEditorT()hook见 wrappers/react-wrapper/src/hotEditor.tsx向 render prop 注入{ value, setValue, finishEditing, isOpen, row, col, mainElementRef }。其中setValue在更新 React 状态的同时会把值同步写回 Handsontable 原生编辑器实例hotCustomEditorInstanceRef.current?.setValue(newValue)而finishEditing()则调用原生实例的finishEditing()从而触发 Handsontable 的afterChange等后续数据流。整个桥接链路由makeEditorClasswrappers/react-wrapper/src/hotEditor.tsx生成的一个继承自Handsontable.editors.BaseEditor的CustomEditor类完成React 组件因此可以无缝替换 Handsontable 原生编辑器。EditorComponent还支持onPrepare、onOpen、onClose、onFocus等生命周期回调以及shortcuts快捷键配置下文增强部分会用到onPrepare。第 4 步添加自定义渲染器View Mode Renderer使用 React 组件作为单元格渲染器使非编辑态也显示星形const RatingCellRenderer ({ value }: { value: unknown }) ( div classNamerating-cell StarRating namerating-cell value{Number(value) || 0} editing{false} / /div );要点分析渲染器接收value并用StarRating展示editing{false}使非编辑态的星形不可交互使用独立的name例如rating-cell保证渲染器内 React key 稳定注意渲染器与编辑器共用同一个StarRating组件这正是本方案“一套 UI、两种形态”的核心优势——编辑态与只读态的视觉完全一致。第 5 步添加校验器Validator可选校验评分是否落在允许范围内例如 0-100const ratingValidator (value: string | number, callback: (valid: boolean) void) { const parsed parseInt(String(value)); callback(parsed 0 parsed 100); };如果采用严格的 1-5 星量表改用parsed 1 parsed 5即可。说明Handsontable 的校验器是异步回调风格——无论值来自编辑器还是粘贴等操作都会经过校验器通过callback(valid)报告结果。校验失败时单元格会进入无效态invalid并在事件流中触发afterValidate便于进一步给出提示。第 6 步添加样式Styling让星形评分在单元格与编辑器中都贴合网格主题.star-rating { display: inline-flex; gap: 1px; } .star-rating .star { font-size: 18px; color: #d3d3d3; line-height: 1; cursor: default; user-select: none; transition: color 0.1s; } .rating-editor .star-rating .star { cursor: pointer; } .star-rating .star.filled { color: #ffb400; } .rating-cell { display: flex; align-items: center; margin: 3px 0 0 -1px; } .rating-editor { display: flex; align-items: center; height: 100%; box-sizing: border-box !important; border: none; border-radius: 0; box-shadow: inset 0 0 0 var(--ht-cell-editor-border-width, 2px) var(--ht-cell-editor-border-color, #1a42e8), 0 0 var(--ht-cell-editor-shadow-blur-radius, 0) 0 var(--ht-cell-editor-shadow-color, transparent); background-color: var(--ht-cell-editor-background-color, #ffffff); padding: var(--ht-cell-vertical-padding, 4px) var(--ht-cell-horizontal-padding, 8px); font-family: var(--ht-font-family, inherit); font-size: var(--ht-font-size, 14px); line-height: var(--ht-line-height, 1.5); }要点分析.star-rating负责本地星形组件的横向布局.star-rating .star.filled为已选中星形着色.rating-cell在非编辑态下将星形与单元格对齐.rating-editor使用 Handsontable 的 CSS 变量--ht-cell-editor-border-width、--ht-cell-editor-background-color、--ht-cell-vertical-padding等均带默认值兜底来适配焦点边框、背景与内边距使编辑器外观与网格主题一致切换深色/浅色主题时无需改动样式第 7 步准备示例数据Sample Data使用带rating属性的数据可按需添加其他列。以商品表为例export const data [ { product: Dashboard Pro, category: Analytics, rating: 5, reviews: 342, price: 49 }, { product: Form Builder, category: Tools, rating: 4, reviews: 218, price: 29 }, { product: Chart Engine, category: Analytics, rating: 3, reviews: 156, price: 39 }, { product: Auth Module, category: Security, rating: 5, reviews: 89, price: 19 }, { product: File Manager, category: Storage, rating: 2, reviews: 64, price: 15 }, { product: Email Service, category: Communication, rating: 4, reviews: 275, price: 25 }, { product: Search Index, category: Tools, rating: 1, reviews: 31, price: 35 }, { product: Cache Layer, category: Infra, rating: 4, reviews: 112, price: 20 }, ];要点分析每行包含product、category、rating、reviews、price字段rating列使用星级编辑器与渲染器其他列可继续使用文本或数字类型第 8 步接入 HandsontableUse in Handsontable将编辑器、渲染器、校验器绑定到 rating 列const ExampleComponent () { return ( HotTable data{data} colHeaders{[Product, Category, Rating, Reviews, Price]} autoRowSize{true} rowHeaders{true} heightauto width100% autoWrapRow{true} headerClassNamehtLeft licenseKeynon-commercial-and-evaluation HotColumn dataproduct typetext width{240} / HotColumn datacategory typetext width{120} / HotColumn datarating width{150} editor{RatingEditor} renderer{RatingCellRenderer} validator{ratingValidator} / HotColumn datareviews typenumeric width{80} / HotColumn dataprice typenumeric width{80} / /HotTable ); };要点分析editor{RatingEditor}—— 单元格激活时启用星级评分编辑器renderer{RatingCellRenderer}—— 非编辑态显示星形validator{ratingValidator}—— 确保评分在允许范围如 0-100内datarating—— 绑定每行数据中的rating属性关键特性编辑态与非编辑态都显示星形评分以数字1-5存储支持校验且全程 TypeScript 类型安全完整可运行示例见仓库中的 example1.tsxTypeScript 版、example1.jsxJavaScript 版及配套样式 example1.css。在 JSX 版中EditorComponent不带泛型参数即可正常使用。工作原理完整流程How It Works - Complete Flow初始渲染RatingCellRenderer按当前评分显示星形例如 3 颗实心星用户双击或按 Enter编辑器打开编辑器打开EditorComponent在单元格位置显示星形选择器星级展示StarRating显示当前值空星表示剩余刻度用户交互悬停星形 →onStarHover通过setValue更新预览点击星形 →onStarClick保存值并调用finishEditing()校验ratingValidator执行例如检查值是否在 0-100 之间保存数字值写入单元格编辑器关闭RatingCellRenderer在非编辑态显示更新后的星形结合源码看第 3 步的“位置对齐”由EditorComponent内部的applyEditorPositionwrappers/react-wrapper/src/hotEditor.tsx完成——它读取被编辑单元格的getBoundingClientRect()把编辑器绝对定位到单元格上方并挂载afterScrollHorizontally/afterScrollVertically钩子滚动时自动跟随刷新位置单元格不可用时会自动关闭编辑器。增强功能Enhancements1. 自定义星级数量改为 10 分制等任意刻度interface StarRatingProps { name: string; value: number; starCount?: number; editing?: boolean; onStarHover?: (value: number) void; onStarClick?: (value: number) void; } function StarRating({ name, value, starCount 5, editing true, onStarHover, onStarClick }: StarRatingProps) { const stars Array.from({ length: starCount }, (_, index) index 1); return ( div classNamestar-rating aria-label{Rating: ${value} out of ${starCount}} {stars.map((star) ( span key{${name}-${star}} className{star value ? star filled : star} onMouseEnter{editing ? () onStarHover?.(star) : undefined} onClick{editing ? () onStarClick?.(star) : undefined} ★ /span ))} /div ); }2. 自定义星形颜色按需调整配色.star-rating .star { color: #e0e0e0; } .star-rating .star.filled { color: #ffd700; }3. 替代方案基于 HTML 的渲染器主示例在非编辑态使用 React 组件RatingCellRenderer。如果你更倾向于非 React 渲染器可使用rendererFactoryimport { rendererFactory } from handsontable/renderers; const starRenderer rendererFactory(({ td, value }) { const rating Number(value) || 0; const stars ★.repeat(rating) ☆.repeat(5 - rating); td.innerHTML div style font-size: 1.2em; color: #ffb400; letter-spacing: 2px; ${stars}/div ; }); // Use in HotColumn HotColumn datarating width{150} editor{RatingEditor} renderer{starRenderer} /源码佐证rendererFactory定义于 handsontable/src/renderers/factory.ts它把标准渲染器函数签名instance, td, row, column, prop, value, cellProperties包装成更易用的对象参数回调仓库测试 handsontable/src/renderers/tests/index.spec.js 也验证了用该工厂创建自定义渲染器的用法。注意渲染器需直接操作tdDOM本例用innerHTML因此返回的仍是 Handsontable 原生渲染器而非 React 组件。4. 从单元格属性读取配置进阶借助onPrepare实现按列定制星级数量const RatingEditor () { const [starCount, setStarCount] useState(5); const onPrepare (_row, _column, _prop, _TD, _originalValue, cellProperties) { if (cellProperties.starCount ! null) { setStarCount(cellProperties.starCount); } }; return ( div classNamerating-editor EditorComponentnumber onPrepare{onPrepare} {({ value, setValue, finishEditing }) ( StarRating namerating starCount{starCount} value{Number(value) || 0} onStarHover{(nextValue) setValue(nextValue)} onStarClick{(nextValue) { setValue(nextValue); finishEditing(); }} / )} /EditorComponent /div ); }; // Use with different star counts per column HotColumn editor{RatingEditor} starCount{5} datarating titleRating (1-5) / HotColumn editor{RatingEditor} starCount{10} datascore titleScore (1-10) /原理说明onPrepare是 Handsontable 编辑器生命周期中“编辑器实例准备就绪”的钩子。在 wrappers/react-wrapper/src/hotEditor.tsx 中EditorComponent把onPrepare透传给底层编辑器实例其第六个参数cellProperties即当前单元格的完整配置对象——因此可以通过HotColumn上的自定义属性如starCount按列注入不同配置。5. 处理空值确保组件能正确处理undefined或nullvalue{Number(value) || 0}当单元格无值时显示空星。无障碍Accessibility本地StarRating组件在评分容器上设置了aria-label。如需键盘支持可将每颗星渲染为按钮button typebutton className{star value ? star filled : star} onMouseEnter{editing ? () onStarHover?.(star) : undefined} onClick{editing ? () onStarClick?.(star) : undefined} aria-label{Set rating to ${star}} ★ /button键盘导航建议Tab聚焦到编辑器方向键添加按键处理器后可在星形间导航Enter/Space选择星形Escape取消编辑性能考量Performance Considerations为什么这套方案是快的无外部评分包星级 UI 只依赖一个轻量本地组件React 虚拟 DOM仅当值变化时才发生更新聚焦的回调onStarHover与onStarClick各司其职职责单一无多余重渲染编辑器关闭即卸载从实现层面看EditorComponent的根 div 在关闭时被设置为display: nonewrappers/react-wrapper/src/hotEditor.tsx编辑器只在需要时可见避免了对网格渲染管线造成持续负担悬停预览仅走 React 内部的setValue状态更新并不会触发 Handsontable 的单元格重渲染。TypeScript 支持TypeScript SupportEditorComponent是完整类型化的。为数字评分指定值类型EditorComponentnumber {({ value, setValue, finishEditing }) { // TypeScript knows value is number | undefined // TypeScript knows setValue accepts number return ( StarRating namerating value{Number(value) || 0} onStarHover{(nextValue) setValue(nextValue)} onStarClick{(nextValue) { setValue(nextValue); finishEditing(); }} / ); }} /EditorComponent借助泛型numbervalue被推断为number | undefined、setValue只接受number从而在编译期杜绝把字符串或错误类型写入评分单元格。最佳实践Best Practices将值强转为数字—— 单元格值可能是字符串统一用Number(value) || 0处理提供nameprop—— 编辑器与渲染器使用不同名称如rating与rating-cell保证 React key 稳定点击时调用finishEditing()—— 星形点击即确认选择并关闭编辑器用onStarHover做预览—— 提交前展示选择结果改善交互体验使用自定义渲染器——RatingCellRenderer配合editing{false}在非编辑态显示星形保持 UI 一致添加校验器—— 用ratingValidator限定值域如 0-100 或 1-5并即时反馈你学到了什么What you learned你创建了一个本地StarRating组件并将其集成为 Handsontable 在 React 中的单元格编辑器用EditorComponent的 render prop 模式管理悬停预览与点击确认用 React 组件渲染器在非编辑态显示星形。整个过程不依赖任何外部评分库数值以数字形式存储并可选配校验器保障数据合法性。下一步Next stepsStar Rating (JavaScript) —— 同一思路的 JavaScript 版本使用editorFactory与 SVG 星形同样零外部依赖Star Rating Editor (Angular) —— 基于HotCellEditorAdvancedComponent的 Angular 版本Colorful Picker (React) —— 另一个 ReactEditorComponent示例演示颜色选择器【免费下载链接】handsontableJavaScript Data Grid / Data Table with a Spreadsheet Look Feel. Works with React, Angular, and Vue. Supported by the Handsontable team ⚡项目地址: https://gitcode.com/gh_mirrors/ha/handsontable创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表