- 前端
- UI组件
【免费下载链接】handsontable
JavaScript Data Grid / Data Table with a Spreadsheet Look & Feel. Works with React, Angular, and Vue. Supported by the Handsontable team ⚡
本篇指南基于 Handsontable 官方仓库中的 Angular 综合示例工程(位于 examples/next/docs/angular-wrapper/demo)展开。该工程是一个"通用目的"(general purpose)的演示项目,集中展示了 Handsontable 在 Angular 中最受欢迎的核心能力——从单元格类型、右键菜单、筛选排序,到行列操作与全局配置。读完本文,你将掌握如何安装依赖、启动开发服务器、运行冒烟测试,以及如何解读工程内每一处 GridSettings 配置背后的含义,并了解将该示例独立 fork 到自有仓库的完整流程。
工程定位:一个展示"最流行功能"的 Angular Demo
这个 demo 不是 Hello World,而是一张功能密集的"功能陈列桌"。它的模板极其精简,核心逻辑全部集中在两个 TypeScript 文件中:组件类 app.component.ts 与全局配置 app.config.ts。模板 app.component.html 中只有一行组件标签:
<div> <hot-table [data]="initialData" [settings]="gridSettings"></hot-table> </div>这种"模板极简、配置集中"的组织方式本身就是 Handsontable Angular Wrapper 推荐的使用范式:通过[data]属性绑定数据源,通过[settings]属性绑定完整的网格配置对象,业务逻辑与表现层彻底解耦。
安装与运行:三步走
安装依赖
在示例工程目录下执行:
npm install该命令会安装 package.json 中声明的全部依赖。从依赖清单可以看到本工程的典型技术栈:
- Angular 运行时:
@angular/core、@angular/common、@angular/forms、@angular/router等(均使用latest标签); - 核心库:
handsontable(网格引擎本体)与@handsontable/angular-wrapper(Angular 官方封装层); - 辅助库:
moment(日期处理)、rxjs、tslib、zone.js; - 测试工具链:
jasmine、jasmine-console-reporter、puppeteer(无头浏览器)、http-server。
其中handsontable与@handsontable/angular-wrapper均为latest版本。需要说明的是:next目录下的示例依赖本地构建的handsontable与 wrapper 包(通过工作区符号链接注入),因此在 monorepo 根目录跑next示例前,通常需要先构建根级包(详见 examples/README.md 的 Development 章节)。
启动开发服务器
npm run start该命令实际执行的是ng serve --port 8080(见 package.json),启动后访问:
http://localhost:8080即可在浏览器中看到完整的 Handsontable 网格。Angular CLI 的开发服务器自带热重载,修改src下的代码后页面会自动刷新。
运行测试
测试采用"先起服务、再跑用例"的两段式流程:
npm run start # 先启动开发服务器 npm run test # 服务器运行后另开终端执行npm run test实际执行node spec/support/jasmine.config.js,通过 Jasmine 驱动 Smoke.spec.js 中的冒烟用例。该用例的核心逻辑如下:
- 通过 Puppeteer 启动无头 Chromium(
args: ['--no-sandbox', '--disable-setuid-sandbox']); - 访问
process.env.TEST_URL || 'http://localhost:8080'; - 断言页面中存在
.handsontable td元素,即网格真实渲染出了单元格。
it('should render Handsontable', async () => { const hotCell = await page.$('.handsontable td'); await expect(hotCell).toBeTruthy(); });这是一个典型的"渲染冒烟测试":只要网格没崩、DOM 里有表格单元格,测试即通过,用于在示例交付前快速兜底。
逐项拆解 GridSettings:demo 展示了哪些能力
demo 的全部功能配置集中在 app.component.ts 的gridSettings对象中。下面按功能族逐项解读,这些配置可直接复制到你的 Angular 工程中。
尺寸与表头
height: 450, colWidths: [180, 220, 140, 120, 120, 120, 140], colHeaders: [ "Company Name", "Name", "Sell date", "In stock", "Quantity", "Order ID", "Country", ], rowHeaders: true, headerClassName: "htLeft",height: 450:网格固定高度为 450px;colWidths:按列指定宽度数组,与 7 列一一对应;colHeaders:自定义列头文案(数组形式);rowHeaders: true:显示行号列;headerClassName: "htLeft":为表头元素附加 CSS 类,可配合自定义样式实现左对齐等视觉效果。
右键菜单与下拉菜单
contextMenu: [ "cut", "copy", "---------", "row_above", "row_below", "remove_row", "---------", "alignment", "make_read_only", "clear_column", ] as PredefinedMenuItemKey[], dropdownMenu: true,contextMenu:右键菜单项,使用预定义键名(PredefinedMenuItemKey)组装,包括剪切/复制、插入上行/下行/删除行、对齐方式、设为只读、清空列,并用"---------"分隔线分组。这些键名来自handsontable/plugins/contextMenu模块(见文件头部的 import 语句);dropdownMenu: true:开启表头下拉菜单,便于对列执行筛选、排序等操作。
列管理与排序筛选
hiddenColumns: { indicators: true }, multiColumnSorting: true, filters: true,hiddenColumns.indicators: true:允许隐藏列,并在表头显示"列被隐藏"的指示器标记;multiColumnSorting: true:开启多列排序(可同时按多列排序);filters: true:开启基于列的筛选器插件(与dropdownMenu配合使用)。
行交互与编辑体验
manualRowMove: true, manualRowResize: true, manualColumnResize: true, autoRowSize: true, autoWrapRow: true, autoWrapCol: true, navigableHeaders: true, imeFastEdit: true,manualRowMove:允许用户拖拽移动行;manualRowResize/manualColumnResize:允许拖拽调整行高与列宽;autoRowSize:自动根据内容计算行高;autoWrapRow/autoWrapCol:光标在网格边缘自动换行/换列导航;navigableHeaders: true:允许键盘焦点进入表头区域进行导航;imeFastEdit: true:针对中文、日文等使用 IME(输入法)的场景优化快速编辑体验,减少输入法组合键被误触发的概率。
单元格类型:columns 定义
columns: [ { data: 1 }, { data: 3 }, { data: 4, type: "date", allowInvalid: false, dateFormat: { day: "2-digit", month: "2-digit", year: "numeric" }, locale: "en-GB" }, { data: 6, type: "checkbox", className: "htCenter" }, { data: 7, type: "numeric" }, { data: 5 }, { data: 2 }, ],这里演示了三种内置单元格类型:
- date 日期类型:
type: "date",配合dateFormat(使用Intl.DateTimeFormat风格的day/month/year配置)与locale: "en-GB"指定格式化区域;allowInvalid: false表示拒绝非法日期输入; - checkbox 复选框:
type: "checkbox",数据源中对应列的布尔值直接映射为勾选状态,className: "htCenter"使其居中显示; - numeric 数值类型:
type: "numeric",提供数值相关的编辑与格式化行为。
数据源 constants.ts 中每条记录是一个 10 元素数组(含"选中"布尔标记、公司名、国家、产品名、日期、订单号、库存布尔值、数量等),data索引将列映射到对应字段。例如第 0 个布尔字段并不显示为数据列,而是被beforeRenderer钩子用于行的视觉状态(见下文)。
渲染钩子:beforeRenderer 行级高亮
beforeRenderer: addClassesToRows,addClassesToRows定义在 add-classes-to-rows.function.ts 中,是一个标准的 Handsontable 渲染前钩子:在每个单元格渲染前被调用,只在每行第一个可见单元格(column === 0)时操作,根据数据第 0 个布尔字段的值,通过Handsontable.dom.addClass/removeClass为整行<tr>添加或移除selected样式类,从而实现"按数据标记高亮整行"的效果:
if (cellProperties.instance.getDataAtRowProp(row, "0")) { Handsontable.dom.addClass(parentElement, SELECTED_CLASS); } else { Handsontable.dom.removeClass(parentElement, SELECTED_CLASS); }这是将beforeRenderer与自定义 CSS 类结合做行级视觉反馈的典型范例。
全局配置:注册模块与许可证注入
与组件级配置不同,app.config.ts 演示了 Angular 应用启动阶段的全局初始化:
import { registerAllModules } from "handsontable/registry"; registerAllModules();registerAllModules()一次性注册 Handsontable 的全部插件模块,让上文中contextMenu、filters、multiColumnSorting、hiddenColumns等插件无需逐一手动导入即可生效——这是 demo 这类"全功能展示"场景的便捷做法;在生产环境中,官方建议按需导入模块以控制打包体积。
随后通过依赖注入提供全局 Handsontable 配置:
const globalHotConfig: HotGlobalConfig = { license: NON_COMMERCIAL_LICENSE, }; export const appConfig: ApplicationConfig = { providers: [ provideZoneChangeDetection({ eventCoalescing: true }), { provide: HOT_GLOBAL_CONFIG, useValue: globalHotConfig }, ], };HOT_GLOBAL_CONFIG是 wrapper 暴露的全局配置 InjectionToken(实现位于 hot-global-config.service.ts),通过它可以在应用级统一注入许可证,而不必在每个<hot-table>组件上重复配置(这也是 wrapper 文档明确推荐的做法,见 wrappers/angular-wrapper/AGENTS.md);NON_COMMERCIAL_LICENSE是仓库内置的非商业许可证常量;provideZoneChangeDetection({ eventCoalescing: true })启用 Angular 的事件合并(event coalescing),减少变更检测触发次数。
应用入口 main.ts 使用bootstrapApplication(AppComponent, appConfig)引导独立(standalone)组件,AppComponent通过imports: [HotTableModule]引入网格能力,而无需NgModule。
将示例 fork 到独立仓库
该 demo 位于 Handsontable 的 monorepo 中。官方提供了两种"分叉"方式(见原文档 Forking 章节):
- fork 整个仓库:适合想保留所有示例与工作区结构的场景;
- 把示例单独复制到一个新仓库:详细步骤见 examples/README.md 的Copying an example to a separate repo章节。
复制到独立仓库时有一个关键注意事项:monorepo 的 npm workspace 可能在示例的node_modules中放置符号链接,因此在复制前应删除该目录,复制到目标位置后重新执行npm install生成干净的依赖树。官方给出的操作流程大致为:克隆仓库 → 进入目标示例目录 → 删除node_modules→ 将示例目录复制到仓库外的目标位置 → (可选)git init初始化新仓库 →npm install→npm run start。
其他示例与运行入口
如果你希望查看更多 Angular 场景,同目录下还提供了 basic-example(最小化入门)与>赞
- 前端
- UI组件
【免费下载链接】handsontable
JavaScript Data Grid / Data Table with a Spreadsheet Look & Feel. Works with React, Angular, and Vue. Supported by the Handsontable team ⚡
相关推荐
在 Angular 中集成 Handsontable:官方 Demo 的运行、测试与源码剖析
在 Angular 中集成 Handsontable:官方 Demo 的运行、测试与源码剖析 导读 本文围绕 Handsontable 仓库中面向 Angula
前端UI组件Handsontable JavaScript 综合示例 Demo 项目解析:安装、运行与测试
Handsontable JavaScript 综合示例 Demo 项目解析:安装、运行与测试 本指南以 Handsontable 官方仓库中的通用示例项目 e
前端UI组件Handsontable Angular 快速上手:用 basic-example 构建你的第一个表格应用
Handsontable Angular 快速上手:用 basic example 构建你的第一个表格应用 本篇技术指南以仓库中的 examples/next/
前端UI组件