從 Handsontable 15.3 遷移到 Handsontable 16.0,于 09/07/2025 發(fā)布。
更多關(guān)于此版本的信息,請(qǐng)參閱 16.0.0 版本的博客文章。
1. 介紹新的 DOM 結(jié)構(gòu)
在 Handsontable 16.0 中,我們改變了表格在 DOM 中的掛載方式。以前,您提供的容器 <div> 成為表格的根元素?,F(xiàn)在,該容器作為一個(gè)掛載點(diǎn),Handsontable 在其中創(chuàng)建并注入自己的根元素。
以下是新舊 DOM 結(jié)構(gòu)的并排比較:
舊的 DOM 結(jié)構(gòu):
body
├── #example.ht-wrapper.handsontable // Root Container/Element
│ ├── .htFocusCatcher // Focus Catcher (top)
│ ├── Data grid content
│ └── . htFocusCatcher // Focus Catcher (down)
├── .hot-display-license-info // License key notification bar
└── Context menus, dropdowns, pop-ups, sidebars
(absolutely positioned elements)
新的 DOM 結(jié)構(gòu):
body
├── #example // Root Wrapper
│ └── .ht-root-wrapper // Root Element
│ ├─ . htFocusCatcher // Focus Catcher (top)
│ ├── .ht-wrapper.handsontable // Root Container
│ │ └── Data grid content
│ ├── . htFocusCatcher // Focus Catcher (down)
│ ├── .hot-display-license-info // License key notification bar
└── .ht-portal // Portal Element
└── Context menus, dropdowns, pop-ups, sidebars
(absolutely positioned elements)
關(guān)鍵變化:
2. 更新了 CSS 變量
在 Handsontable 16.0 中,我們對(duì) CSS 變量系統(tǒng)進(jìn)行了重大改進(jìn),調(diào)整了主題顏色、變量順序,并提供了更好的定制選項(xiàng)。以下是主要的變更:
新的 CSS 變量
我們引入了新的變量,讓自定義變得更容易:
l--ht-letter-spacing: 控制字母間距,以改善可讀性和視覺(jué)外觀。
l--ht-radio-*: 使單選輸入的樣式更準(zhǔn)確。
l--ht-cell-read-only-background-color: 實(shí)現(xiàn)更好的只讀單元格背景自定義。
l--ht-checkbox-indeterminate: 允許您對(duì)復(fù)選框的不定狀態(tài)進(jìn)行風(fēng)格設(shè)置。
重命名的 CSS 變量
我們已將部分變量重命名為更一致的名稱(chēng):
|
舊變量名稱(chēng) |
新變量名稱(chēng) |
|
--ht-icon-active-button-border-color |
--ht-icon-button-active-border-color |
|
--ht-icon-active-button-background-color |
--ht-icon-button-active-background-color |
|
--ht-icon-active-button-icon-color |
--ht-icon-button-active-icon-color |
|
--ht-icon-active-button-hover-border-color |
--ht-icon-button-active-hover-border-color |
|
--ht-icon-active-button-hover-background-color |
--ht-icon-button-active-hover-background-color |
|
--ht-icon-active-button-hover-icon-color |
--ht-icon-button-active-hover-icon-color |
遷移說(shuō)明
如果您在版本 15.3 中使用了自定義 CSS 變量,您需要:
1. 檢查您的自定義變量名稱(chēng)是否符合新的命名規(guī)范
2. 更新變量引用以使用新的單選按鈕輸入(僅當(dāng)復(fù)選框變量發(fā)生更改時(shí))
3. 利用新變量實(shí)現(xiàn)更精細(xì)的控制
3. 更新自定義邊框的位置
在版本 16.0 中,我們更新了自定義邊框的定位方式,以提高準(zhǔn)確性和一致性。此更改會(huì)影響邊框的視覺(jué)定位,特別是對(duì)于具有自定義邊框的單元格。
發(fā)生了什么變化?
邊框位置已調(diào)整,以防止與相鄰單元格和標(biāo)題重疊。
為何這是重大變更?
雖然可能性極低,但若您的應(yīng)用依賴(lài)特定邊框位置,或基于邊框位置實(shí)現(xiàn)了自定義樣式,可能需要更新樣式。
版本 16.0 中邊框的視覺(jué)外觀與版本 15.3 相比將略有不同。
遷移說(shuō)明
無(wú)需修改代碼——新版本會(huì)自動(dòng)處理這些改進(jìn)。
4. 切換至新的 Angular 包裝器(適用于 Angular 16+)
Handsontable 16.0 引入了全新的 Angular 包裝器。該包裝器旨在與現(xiàn)代 Angular 應(yīng)用程序?qū)崿F(xiàn)更佳集成并提升開(kāi)發(fā)體驗(yàn)。若您使用 Angular 16 或更高版本,建議遷移至新包裝器。
為何要切換至新 Angular 包裝器?
• 組件化架構(gòu):新包裝器采用 Angular 的組件化架構(gòu),允許您將自定義編輯器和渲染器實(shí)現(xiàn)為 Angular 組件。
• 改進(jìn)的 TypeScript 支持:新包裝器提供了更完善的 TypeScript 定義。
• 獨(dú)立組件支持:新包裝器全面支持 Angular 的獨(dú)立組件,使其在現(xiàn)代 Angular 應(yīng)用中更易于使用。
• 全局配置:新包裝器通過(guò)依賴(lài)注入提供了更好的全局配置管理。
• 模板語(yǔ)法:簡(jiǎn)化的模板語(yǔ)法減少了冗余代碼,使配置更易于維護(hù)。
• 實(shí)例訪(fǎng)問(wèn):現(xiàn)在可以通過(guò) ViewChild 直接訪(fǎng)問(wèn) Handsontable 實(shí)例。
步驟 1:更新包依賴(lài)項(xiàng)
用新包裝器包替換舊的 Angular 包裝器包:
npm uninstall @handsontable/angular
npm install @handsontable/angular-wrapper
步驟 2:更新組件配置
將所有配置選項(xiàng)移動(dòng)到組件中的 GridSettings 對(duì)象中。
舊的包裝組件:
@Component({
selector: ‘app-root’,
template: `
<hot-table
[data]=“data”
[colHeaders]=“true”
[licenseKey]=“‘non-commercial-and-evaluation’”>
<hot-column data="id" [readOnly]=“true” title="ID"></hot-column>
<hot-column data="name" title="Full name"></hot-column>
</hot-table>
`})export class AppComponent {
data = //...}
新包裝組件:
import { GridSettings, HotTableModule } from ‘@handsontable/angular-wrapper’;
@Component({
standalone: true,
imports: [HotTableModule],
template: `<hot-table [data]=“data” [settings]=“gridSettings” />`})export class AppComponent {
data = //...;
gridSettings: GridSettings = {
colHeaders: true,
licenseKey: ‘non-commercial-and-evaluation’,
columns: [
{ data: ‘id’, readOnly: true, title: ‘ID’ },
{ data: ‘name’, title: ‘Full name’ },
]
};}
步驟 3:更新表格實(shí)例引用
您引用和與 Handsontable 實(shí)例交互的方式已發(fā)生變化。
舊的包裝器實(shí)例引用:
export class AppComponent {
private hotRegisterer = new HotTableRegisterer();
id = ‘hotInstance’;
swapHotData() {
this.hotRegisterer.getInstance(this.id).loadData([[‘new’, ‘data’]]);
}}
新的包裝器實(shí)例引用:
import { HotTableComponent } from ‘@handsontable/angular-wrapper’;
export class AppComponent {
@ViewChild(HotTableComponent, { static: false })
hotTable!: HotTableComponent;
swapHotData() {
this.hotTable.hotInstance!.loadData([[‘new’, ‘data’]]);
}}
步驟 4:更新全局設(shè)定
新的包裝器提供更好的全局設(shè)定管理。
舊包裝器的全局配置:
// Configuration was typically done per componentexport class AppComponent {
hotSettings = {
licenseKey: 'non-commercial-and-evaluation',
};}
使用 ApplicationConfig 的新包裝器全局配置:
import { ApplicationConfig } from '@angular/core';import { HOT_GLOBAL_CONFIG, HotGlobalConfig, NON_COMMERCIAL_LICENSE } from '@handsontable/angular-wrapper';
const globalHotConfig: HotGlobalConfig = {
license: NON_COMMERCIAL_LICENSE,
language: 'en',
themeName: 'ht-theme-main',};
export const appConfig: ApplicationConfig = {
providers: [
{ provide: HOT_GLOBAL_CONFIG, useValue: globalHotConfig },
],};
使用服務(wù)的新包裝器全局配置:
import { HotGlobalConfigService, NON_COMMERCIAL_LICENSE } from '@handsontable/angular-wrapper';
export class AppComponent {
constructor(private hotConfig: HotGlobalConfigService) {
this.hotConfig.setConfig({
themeName: 'ht-theme-main',
});
}}
步驟 5:更新自定義編輯器
新的包裝器在傳統(tǒng)以類(lèi)為基礎(chǔ)的方式之外,引入了以元件為基礎(chǔ)的編輯器。
舊包裝器自定義編輯器:
import { TextEditor } from 'handsontable/editors/textEditor';
export class CustomEditor extends TextEditor {
override createElements() {
super.createElements();
this.TEXTAREA = document.createElement('input');
this.TEXTAREA. setAttribute('placeholder', 'Custom placeholder');
this.TEXTAREA.setAttribute('data-hot-input', 'true');
this.textareaStyle = this.TEXTAREA.style;
this.TEXTAREA_PARENT.innerText = '';
this.TEXTAREA_PARENT.appendChild(this.TEXTAREA);
}}
// Usage in settings
hotSettings = {
columns: [{ editor: CustomEditor }]};
新的封裝元件式編輯器:
import { Component, ViewChild, ElementRef, ChangeDetectionStrategy } from '@angular/core';
import { FormsModule } from '@angular/forms';
import { HotCellEditorComponent } from '@handsontable/angular-wrapper';
@Component({
selector: 'app-custom-editor',
imports: [FormsModule],
standalone: true,
changeDetection: ChangeDetectionStrategy.OnPush,
template: `
<div style="width: 100%; overflow: hidden">
<input
#inputElement
type="text"
[value]="getValue()"
(keydown)="onKeyDown($event)"
style="width: 100%; box-sizing: border-box"
/>
</div>
`,})export class CustomEditorComponent extends HotCellEditorComponent<string> {
@ViewChild('inputElement') inputElement! ElementRef;
onKeyDown(event: KeyboardEvent): void {
const target = event.target as HTMLInputElement;
this.setValue(target.value);
}
onFocus(): void {
this.inputElement.nativeElement.select();
}}
// Usage in settings
gridSettings: GridSettings = {
columns: [{ editor: CustomEditorComponent }]};
步驟 6:更新自定義渲染器
新的包裝器除了支持基于函數(shù)的渲染器外,還支持基于元件的渲染器。
舊的包裝器自定義渲染器:
export class AppComponent {
hotSettings = {
columns: [{
renderer(instance, td, row, col, prop, value, cellProperties) {
const img = document.createElement('img');
img.src = value;
td.innerText = 『』;
td.appendChild(img);
return td;
}
}]
};}
新的封裝元件式渲染器:
import { Component, ChangeDetectionStrategy } from '@angular/core';
import { HotCellRendererComponent } from '@handsontable/angular-wrapper';
@Component({
selector: 'app-custom-renderer',
template: `
<div class="container" [style.backgroundColor]="value">
{{ value }}
</div>
`,
styles: [`
.container {
height: 100%;
width: 100%;
}
:host {
justify-content: center;
align-items: center;
width: 100%;
height: 100%;
padding: 0;
}
`],
standalone: true,
changeDetection: ChangeDetectionStrategy.OnPush})export class CustomRendererComponent extends HotCellRendererComponent<string> {}
// Usage in settings
gridSettings: GridSettings = {
columns: [{ renderer: CustomRendererComponent }]};
步驟 7:更新 CSS 導(dǎo)入
確認(rèn)您導(dǎo)入的主題 CSS 檔案是正確的。
CSS 導(dǎo)入 (兩個(gè)包裝器相同):
@import'handsontable/styles/handsontable.min.css';
@import 'handsontable/styles/ht-theme-main.min.css';
或在 angular.json 中:
{
"styles": [
"src/styles.scss",
"node_modules/handsontable/styles/handsontable.min.css",
"node_modules/handsontable/styles/ht-theme-main.min.css"
]}
常見(jiàn)遷移問(wèn)題
問(wèn)題:無(wú)法找到模塊 ‘@handsontable/angular’
解決方案:確保您已將導(dǎo)入更新為使用 @handsontable/angular-wrapper
問(wèn)題:hot-column 未被識(shí)別
解決方案:新包裝器不再使用 <hot-column>。在設(shè)置對(duì)象中將列配置移動(dòng)到列數(shù)組中。
問(wèn)題: “未定義HotTableRegisterer ”
解決方案: 使用 @ViewChild(HotTableComponent) 并訪(fǎng)問(wèn) hotInstance 屬性。
問(wèn)題: “自定義渲染器無(wú)法正常工作”
解決方案: 將基于函數(shù)的渲染器轉(zhuǎn)換為繼承自 HotCellRendererComponent 的組件。
問(wèn)題:自定義編輯器無(wú)法正常工作
解決方案:將基于類(lèi)的編輯器轉(zhuǎn)換為繼承自 HotCellEditorComponent 的組件。
本遷移指南涵蓋了舊版和新版 Angular 包裝器之間的主要變化。新版包裝器提供了與現(xiàn)代 Angular 模式更好的集成、改進(jìn)的類(lèi)型安全性和更易于維護(hù)的代碼庫(kù)。
5. 引入 pnpm 作為倉(cāng)庫(kù)包管理器
自2025年7月1日起,我們已切換至pnpm作為倉(cāng)庫(kù)的主要包管理器。
隨著倉(cāng)庫(kù)中包數(shù)量的增加,依賴(lài)項(xiàng)數(shù)量也隨之增長(zhǎng)。這使得管理依賴(lài)項(xiàng)并以一致的方式安裝它們變得困難。為解決此問(wèn)題,我們已切換至使用pnpm作為主要包管理器。
這會(huì)影響我嗎?
除非您需要?jiǎng)?chuàng)建Handsontable或任何包裝器的自定義構(gòu)建,否則此更改不會(huì)影響您。
如果您正在進(jìn)行此類(lèi)操作,則需要使用 pnpm 安裝主倉(cāng)庫(kù)依賴(lài)項(xiàng)。
注意:示例和文檔包仍由 npm 管理,不屬于主 pnpm 工作區(qū)。
如何遷移?
1.安裝 pnpm,版本需與根目錄 package.json 文件中 packageManager 字段定義的版本一致。
2.如果您之前在倉(cāng)庫(kù)的克隆版本上進(jìn)行過(guò)開(kāi)發(fā),需要?jiǎng)h除 node_modules 目錄、package-lock.json 文件等。
您可以通過(guò)運(yùn)行 npm run clean:node_modules -- --keep-lockfiles 來(lái)完成此操作。
3.運(yùn)行 pnpm install 安裝依賴(lài)項(xiàng)。
4.所有 npm 命令仍然可用,因此您可以像以前一樣構(gòu)建包,例如通過(guò)運(yùn)行 npm run build。
京ICP備09015132號(hào)-996 | 違法和不良信息舉報(bào)電話(huà):4006561155
© Copyright 2000-2026 北京哲想軟件有限公司版權(quán)所有 | 地址:北京市海淀區(qū)西三環(huán)北路50號(hào)豪柏大廈C2座11層1105室
北京哲想軟件集團(tuán)旗下網(wǎng)站:哲想軟件 | 哲想動(dòng)畫(huà)