在 React 中使用 Handsontable 电子表格组件

您所在的位置:网站首页 js中的属性 在 React 中使用 Handsontable 电子表格组件

在 React 中使用 Handsontable 电子表格组件

2023-04-08 22:48| 来源: 网络整理| 查看: 265

Handsontable 是一个 js 表格组件,并提供了数据绑定、验证、排序、上下文菜单等功能。

它在 7.0 后开始转为付费软件,最后一个开源免费的版本是 6.2.2 。

@handsontable/react 是 Handsontable 的官方 React 包装器,本项目将结合 官方 React 包装器文档 的全部示例,演示其在 umi.js 中的使用,附带中文注释和线上demo。

安装

其中本项目创建和安装过程如下:

1、创建 umi 项目,安装过程中选择使用 dva

yarn create umi yarn install 复制代码

2、安装 Handsontable 社区版 6.2.2 和 React 包装器

npm install [email protected] @handsontable/react 复制代码

3、在 app.js 中引入 Handsontable 样式和中文语言包

import 'handsontable/dist/handsontable.full.css'; import "handsontable/languages/zh-CN"; 复制代码

4、在组件中使用 @handsontable/react

import React from 'react'; import { HotTable } from '@handsontable/react'; class App extends React.Component { constructor(props) { super(props); this.state = { data: [ ['', 'Ford', 'Volvo', 'Toyota', 'Honda'], ['2016', 10, 11, 12, 13], ['2017', 20, 11, 14, 13], ['2018', 30, 15, 12, 13], ], }; } render() { return ( ); } } export default function() { return ; } 复制代码 基础使用 简单示例 import React from 'react'; import { HotTable } from '@handsontable/react'; import Handsontable from 'handsontable'; class App extends React.Component { constructor(props) { super(props); this.state = { handsontableData: Handsontable.helper.createSpreadsheetData(6, 10) }; } render() { return ( ); } } export default function() { return ( ); } 复制代码 使用单个 setting 属性 import React from 'react'; import { HotTable } from '@handsontable/react'; import Handsontable from 'handsontable'; class App extends React.Component { constructor(props) { super(props); this.state = { handsontableData: Handsontable.helper.createSpreadsheetData(6, 10) }; } render() { return ( ); } } export default function() { return ( ); } 复制代码 使用外部按钮控制 table 行为 import React from 'react'; import { HotTable } from '@handsontable/react'; import Handsontable from 'handsontable'; class MyComponent extends React.Component { constructor(props) { super(props); this.state = { settings: { language: 'zh-CN', data: Handsontable.helper.createSpreadsheetData(15, 20), width: 570, height: 220, }, }; } // 通过控制 settings 操作表格行为 handleChange = (setting, states) => { return event => { this.setState({ settings: { [setting]: states[event.target.checked ? 1 : 0], }, }); }; }; render() { return ( Add fixed rows Add fixed columns Enable row headers Enable column headers ); } } export default function() { return ; } 复制代码 自定义右键菜单 import React from 'react'; import { HotTable } from '@handsontable/react'; import Handsontable from 'handsontable'; class App extends React.Component { constructor(props) { super(props); this.hotSettings = { language: 'zh-CN', data: Handsontable.helper.createSpreadsheetData(5, 5), colHeaders: true, contextMenu: { items: { // 右键菜单列表 row_above: { // Insert row above 自定义名称 name: '在此上方插入行(自定义的名称)', }, row_below: {}, // Insert row below separator: Handsontable.plugins.ContextMenu.SEPARATOR, // 分割线 clear_custom: { // 自定义的菜单项 name: '清除所有单元格(自定义菜单)', callback: function() { // this是Handsontable实例 this.clear(); }, }, }, }, }; } render() { return ( ); } } export default function() { return ; } 复制代码 自定义编辑器

添加了自定义编辑器,使用 input 元素的 placeholder 属性。

自定义编辑器部分的代码:

// 自定义编辑器 class CustomEditor extends Handsontable.editors.TextEditor { createElements() { super.createElements(); // 使用 input 元素 this.TEXTAREA = document.createElement('input'); // 定义 placeholder 属性 this.TEXTAREA.setAttribute('placeholder', '自定义的 placeholder'); this.TEXTAREA.className = 'handsontableInput'; this.textareaStyle = this.TEXTAREA.style; Handsontable.dom.empty(this.TEXTAREA_PARENT); this.TEXTAREA_PARENT.appendChild(this.TEXTAREA); } } 复制代码

在 handsontable 中的使用:

import React from 'react'; import { HotTable } from '@handsontable/react'; import Handsontable from 'handsontable'; class App extends React.Component { constructor(props) { super(props); this.hotSettings = { language: 'zh-CN', startRows: 5, columns: [ { editor: CustomEditor } ], colHeaders: true, colWidths: 200 }; } render() { return ( ); } } export default function() { return ( ); } 复制代码 自定义渲染器

它以图像url作为输入,并在单元格中呈现图像。

import React from 'react'; import { HotTable } from '@handsontable/react'; import Handsontable from 'handsontable'; class App extends React.Component { constructor(props) { super(props); this.hotSettings = { language: 'zh-CN', data: [ ['A1', 'http://ecx.images-amazon.com/images/I/51bRhyVTVGL._SL50_.jpg'], ['A2', 'http://ecx.images-amazon.com/images/I/51gdVAEfPUL._SL50_.jpg'], ], columns: [ {}, { renderer: function(instance, td, row, col, prop, value, cellProperties) { const escaped = Handsontable.helper.stringify(value); let img = null; if (escaped.indexOf('http') === 0) { img = document.createElement('IMG'); img.src = value; Handsontable.dom.addEvent(img, 'mousedown', function(event) { event.preventDefault(); }); Handsontable.dom.empty(td); td.appendChild(img); } else { Handsontable.renderers.TextRenderer.apply(this, arguments); } return td; }, }, ], colHeaders: true, rowHeights: 55, }; } render() { return ( ); } } export default function() { return ; } 复制代码 动态切换语言

效果:从表格上方的选择器中选择一种语言,然后打开上下文菜单查看结果。

通过 Handsontable.languages.getLanguagesDictionaries() 获取所有语言,并通过选择动态改变语言设置。

需要注意,返回的语言跟引入的语言包有关,需要在公共位置引入:

import "handsontable/languages/zh-CN"; 复制代码

示例代码如下:

import React from 'react'; import { HotTable } from '@handsontable/react'; import Handsontable from 'handsontable'; class App extends React.Component { constructor(props) { super(props); this.id = 'hot'; this.state = { hotSettings: { data: Handsontable.helper.createSpreadsheetData(5, 10), colHeaders: true, rowHeaders: true, contextMenu: true, }, language: 'zh-CN', }; this.updateHotLanguage = this.updateHotLanguage.bind(this); } componentDidMount() { this.getAllLanguageOptions(); } getAllLanguageOptions() { // 需要引入语言包,即可获取到对应的语言 const allDictionaries = Handsontable.languages.getLanguagesDictionaries(); console.log(allDictionaries,'allDictionaries') const langSelect = document.querySelector('#languages'); langSelect.innerHTML = ''; for (let language of allDictionaries) { langSelect.innerHTML += `${language.languageCode}`; } } updateHotLanguage(event) { this.setState({ language: event.target.value }); } render() { return ( 选择语言: ); } } export default function() { return ; } 复制代码 Redux / Dva 示例

效果:使用Redux状态管理器实现设置,并通过开关控制readOnly切换。

使用了 umi.js ,这里当然也顺便通过 dva 来实现该案例的效果。

建立 model/setting.js 如下:

import Handsontable from 'handsontable'; export default { namespace: 'setting', state: { data: Handsontable.helper.createSpreadsheetData(5, 3), colHeaders: true, rowHeaders: true, readOnly: false, }, reducers: { save(state, action) { return { ...state, ...action.payload }; }, }, effects: { *updateData( { payload: { dataChanges }, }, { select, put }, ) { const data = yield select(state => state.setting.data); const newData = data.slice(0); // eslint-disable-next-line no-unused-vars for (let [row, column, oldValue, newValue] of dataChanges) { newData[row][column] = newValue; } yield put({ type: 'save', payload: { data: newData, }, }); }, *updateReadOnly({ payload: { readOnly } }, { put }) { console.log(readOnly, 'readOnly'); yield put({ type: 'save', payload: { readOnly, }, }); }, }, }; 复制代码

组件代码:

import React from 'react'; import { connect } from 'dva'; import { HotTable } from '@handsontable/react'; class MyComponent extends React.Component { constructor(props) { super(props); this.toggleReadOnly = this.toggleReadOnly.bind(this); this.hotTableComponent = React.createRef(); } componentDidMount() { this.updateReduxPreview(); } componentDidUpdate() { this.updateReduxPreview(); } onBeforeHotChange = (changes, source) => { const { dispatch } = this.props; dispatch({ type: 'setting/updateData', payload: { dataChanges: changes, }, }); return false; }; toggleReadOnly = event => { const { dispatch } = this.props; dispatch({ type: 'setting/updateReadOnly', payload: { readOnly: event.target.checked, }, }); }; updateReduxPreview() { // 此方法仅用作 Redux 的状态的渲染 const previewTable = document.querySelector('#redux-preview table'); let newInnerHtml = ''; for (const [key, value] of Object.entries(this.props.setting)) { newInnerHtml += ``; if (key === 'data' && Array.isArray(value)) { newInnerHtml += `data: `; for (let row of value) { newInnerHtml += ``; for (let cell of row) { newInnerHtml += `${cell}`; } newInnerHtml += ``; } newInnerHtml += ``; } else { newInnerHtml += `${key}: ${value}`; } newInnerHtml += ``; } newInnerHtml += ``; previewTable.innerHTML = newInnerHtml; } render() { return ( {' '} 切换 readOnly dva store 数据: ); } } function mapStateToProps(state) { return { setting: state.setting, }; } export default connect(mapStateToProps)(MyComponent); 复制代码 Referencing the Handsontable instance - 获取 Handsontable 实例

示范了如何从包装器引用Handsontable实例:

为我们的react组件创建一个 ref 为 this.hotTableComponent 从 this.hotTableComponent.current 获取到 wrapper 组件的 ref 对于 wrapper 组件来说, Handsontable 的实例在其 hotInstance 属性 this.hotTableComponent.current.hotInstance.loadData([['new', 'data']]); 复制代码

完整代码如下:

import React from 'react'; import { HotTable } from '@handsontable/react'; import Handsontable from 'handsontable'; class App extends React.Component { constructor(props) { super(props); this.id = 'hot'; this.hotSettings = { language: 'zh-CN', data: Handsontable.helper.createSpreadsheetData(4, 4), colHeaders: true }; this.hotTableComponent = React.createRef(); } swapHotData = ()=> { // this.hotTableComponent.current 获取到 wrapper 组件的 ref // 对于 wrapper 组件来说, Handsontable 的实例在其 hotInstance 属性 this.hotTableComponent.current.hotInstance.loadData([['new', 'data']]); } render() { return ( 加载新数据! ); } } export default function() { return ( ); } 复制代码


【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3