「前端开发」前端表格组件库 HandsonTable.js 常规功能使用教程

4,617 阅读6分钟

🙏废话不多说系列,直接开整🙏

handsontable-main-page-illustration.svg


一、简介

    Handsontable 是一个强大的 JavaScript 表格组件,允许用户创建和管理数据表格。下面是一个简单的使用实例,展示如何在网页中集成 Handsontable

    基本功能: 您可以将 Handsontable 用于所有类型的数据丰富、可访问的应用程序,使用户能够输入、编辑、验证和处理来自各种来源的数据,包括数据库和 API 等远程来源,以及 HTML 文档、Excel 文件、Google 表格和手动输入。

  1. 在线编辑表格对应的数据;

  2. 不仅支持原生的 JS ,还支持 多种不同的前端框架,如 Angular,React,Vue2, Vue3;

  3. 多列排序,过滤数据,导出文件,验证数据,条件格式,合并单元格,拖动单元格和指定列;

二、基本使用

(1)基本使用DEMO

示例步骤:① 引入 handsontable 的 CDN 加载对应的JS和CSS文件组件;② 定义一个二维数组作为基本的初始数据源;

<!DOCTYPE html>
<html lang="zh">
	<head>
		<meta charset="UTF-8">
		<meta name="viewport" content="width=device-width, initial-scale=1.0">
		<title>Handsontable 示例</title>

		<script src="https://cdn.bootcdn.net/ajax/libs/handsontable/14.4.0/handsontable.full.js"></script>
		<link href="https://cdn.bootcdn.net/ajax/libs/handsontable/14.4.0/handsontable.full.css" rel="stylesheet">
		<!-- 
		<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/handsontable/dist/handsontable.full.min.css">
		<script src="https://cdn.jsdelivr.net/npm/handsontable/dist/handsontable.full.min.js"></script>
		-->
		<style>
			#example {
				width: 600px;
				height: 300px;
				overflow: hidden;
			}
		</style>
	</head>
	<body>
		<div id="example"></div>

		<script>
			// 2. 初始化 Handsontable
			const data = [
				["", "Ford", "Tesla", "Toyota", "Honda"],
				["2019", 10, 11, 12, 13],
				["2020", 20, 11, 14, 32],
				["2021", 30, 15, 12, 32]
			];

			const container = document.getElementById('example');
			const hot = new Handsontable(container, {
				data: data,
				colHeaders: true,// 是否展示表头
				rowHeaders: true,// 是否展示行号
				filters: true,// 是否开启列数据过滤筛选功能
				dropdownMenu: true,// 是否开启表头下拉功能(插入行,删除行等)
				contextMenu: true,// 是否开启行数据操作功能菜单
				licenseKey: 'non-commercial-and-evaluation' // 使用非商业和评估许可证
			});
		</script>
	</body>
</html>

基本使用实例效果展示:

handsontableJS.gif

(2)配置相关

A. 开启表头和序号
const hot = new Handsontable(container, {
    data: data,
    colHeaders: true, // 开启表头
    rowHeaders: true, // 开启序号
    licenseKey: 'non-commercial-and-evaluation' // 使用非商业和评估许可证
});
  • 未开启 表头 和 序号 展示

image.png

  • 开启表头和序号

image.png

B. 开启列筛选功能
const hot = new Handsontable(container, {
    data: data,// 表格二维数据(数组)
    colHeaders: true,// 必要前提:开启表头
    dropdownMenu: true,// 【核心】开启列下拉功能(支持向左/向右增加/删除/不显示列等只读操作)
    licenseKey: 'non-commercial-and-evaluation' // 使用非商业和评估许可证
});
  • 表头下拉功能菜单

image.png

C. 开启列数据筛选功能
const hot = new Handsontable(container, {
    data: data,
    colHeaders: true,// 必要前提1
    // rowHeaders: true,
    dropdownMenu: true, // 必要前提2
    filters: true,// 【核心】开启过滤
    licenseKey: 'non-commercial-and-evaluation' // 使用非商业和评估许可证
});
  • 开启表格列数据筛选功能

image.png

D. 开启行数据操作功能
const hot = new Handsontable(container, {
    data: data,
    contextMenu: true, // 【核心】开启单元格数据右键菜单功能选项
    licenseKey: 'non-commercial-and-evaluation' // 使用非商业和评估许可证
});
  • 开启前无操作菜单

image.png

- 开启后行数据右击操作菜单项

image.png

E. 导出配置

完整示例:官方示例教程 Export to CSV - JavaScript Data Grid | Handsontable

<!DOCTYPE html>
<html lang="zh">
	<head>
		<meta charset="UTF-8">
		<meta name="viewport" content="width=device-width, initial-scale=1.0">
		<title>Handsontable 示例</title>

		<script src="https://cdn.bootcdn.net/ajax/libs/handsontable/14.4.0/handsontable.full.js"></script>
		<link href="https://cdn.bootcdn.net/ajax/libs/handsontable/14.4.0/handsontable.full.css" rel="stylesheet">

		<style>
			#example {
				width: 600px;
				height: 300px;
				overflow: hidden;
			}
		</style>
	</head>
	<body>
		<!-- 导入配置1.编写HTML问题 -->
		<div class="example-controls-container">
		  <div class="controls">
		    <button id="export-file">Download CSV</button>
		  </div>
		</div>
		<div id="example"></div>

		<script>
			// 2. 初始化 Handsontable
			const data = [
				["", "Ford", "Tesla", "Toyota", "Honda"],
				["2019", 10, 11, 12, 13],
				["2020", 20, 11, 14, 32],
				["2021", 30, 15, 12, 32]
			];

			const container = document.getElementById('example');
			const hot = new Handsontable(container, {
				data: data,
				colHeaders: true,
				rowHeaders: true,
				dropdownMenu: true,
				filters: true,
				contextMenu: true,
				licenseKey: 'non-commercial-and-evaluation' // 使用非商业和评估许可证
			});
			
			// 导入配置2:设置导入配置属性
			const exportPlugin = hot.getPlugin('exportFile');
			const button = document.querySelector('#export-file');
			button.addEventListener('click', () => {
			  exportPlugin.downloadFile('csv', {
			    bom: false,
			    columnDelimiter: ',',
			    columnHeaders: false,
			    exportHiddenColumns: true,
			    exportHiddenRows: true,
			    fileExtension: 'csv',
			    filename: 'Handsontable-CSV-file_[YYYY]-[MM]-[DD]',
			    mimeType: 'text/csv',
			    rowDelimiter: '\r\n',
			    rowHeaders: true,
			  });
			});
		</script>
	</body>
</html>
  • 导出配置结果示例

image.png

F. 配置常见统计指标行

两个注意事项进行配置:① 元数据二维数组 额外加一行 [null] 用来统计占位;② 定义 handsontable 属性 columnSummary 进行配置;如下实例:

  • 配置统计指标行

image.png

columnSummary 属性说明如下:

  • sourceColumn:需要统计的列【0 表示第一列】;
  • type:统计函数类型(有 sum, min ,  max, count,  average)函数;
  • destinationRow:显示于第N列,前提需要在元数据data数组上增加一个空数组元素 [null] 占位一行用来存放统计的数据;
  • distinationColumn:显示在第几列,一般和 sourceColumn 保持一致即可。当然你可以指定显示在第几列即可。
  • forceNumeric:是否提取数字进行统计。统计的时候只读取指定列的各个数据的数字进行统计。

官方示例地址传送门:Column summary - JavaScript Data Grid | Handsontable

G. 设置单元格注释说明

两个步骤实现:① 配置属性 comments:true;② 配置 指定单元格的定位和相关的注释说明;

const hot = new Handsontable(container, {
    data: data,
    colHeaders: true,
    rowHeaders: true,
    comments:true, // 1.开启注释
    cell:[ // 2.定义指定单元格注释(此处 定义第一行第一列格子数据的说明为“Hello world!”)
        { row: 0, col: 0, comment: { value: 'Hello world!' } }
    ],
    licenseKey: 'non-commercial-and-evaluation' // 使用非商业和评估许可证
});

展示结果示例:

  • 配置指定单元格备注

handsontableJS0001.gif

H. 配置指定行显示数据格式和定义表头

① 定义表头列名;② 按照列顺序配置每一列元素的格式显示(非常常见的一类);

<!DOCTYPE html>
<html lang="zh">
	<head>
		<meta charset="UTF-8">
		<meta name="viewport" content="width=device-width, initial-scale=1.0">
		<title>Handsontable 示例</title>

		<script src="https://cdn.bootcdn.net/ajax/libs/handsontable/14.4.0/handsontable.full.js"></script>
		<link href="https://cdn.bootcdn.net/ajax/libs/handsontable/14.4.0/handsontable.full.css" rel="stylesheet">
		<!-- 
		<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/handsontable/dist/handsontable.full.min.css">
		<script src="https://cdn.jsdelivr.net/npm/handsontable/dist/handsontable.full.min.js"></script>
		-->
		<style>
			#example {
				width: 600px;
				height: 300px;
				overflow: hidden;
			}
		</style>
	</head>
	<body>
		<!-- 导入配置1.编写HTML问题 -->
		<div class="example-controls-container">
			<div class="controls">
				<button id="export-file">Download CSV</button>
			</div>
		</div>
		<div id="example"></div>

		<script>
			// 2. 初始化 Handsontable
			const data = [
				['Mercedes', 'A 160', '01/14/2021', 6999.95],
				['Citroen', 'C4 Coupe', '12/01/2022', 8330],
				['Audi', 'A4 Avant', '11/19/2023', 33900],
				['Opel', 'Astra', '02/02/2021', 7000],
				['BMW', '320i Coupe', '07/24/2022', 30500],
			];

			const container = document.getElementById('example');
			const hot = new Handsontable(container, {
				licenseKey: 'non-commercial-and-evaluation',
				data: [
					['Mercedes', 'A 160', '01/14/2021', 6999.95],
					['Citroen', 'C4 Coupe', '12/01/2022', 8330],
					['Audi', 'A4 Avant', '11/19/2023', 33900],
					['Opel', 'Astra', '02/02/2021', 7000],
					['BMW', '320i Coupe', '07/24/2022', 30500],
				],
				colHeaders: ['Car', 'Model', 'Registration date', 'Price'],
				height: 'auto',
				columns: [{
						type: 'text',
					},
					{
						// 2nd cell is simple text, no special options here
					},
					{
						type: 'date',
						dateFormat: 'MM/DD/YYYY',
						correctFormat: true,
						defaultDate: '01/01/1900',
						// datePicker additional options
						// (see https://github.com/dbushell/Pikaday#configuration)
						datePickerConfig: {
							// First day of the week (0: Sunday, 1: Monday, etc)
							firstDay: 0,
							showWeekNumber: true,
							disableDayFn(date) {
								// Disable Sunday and Saturday
								return date.getDay() === 0 || date.getDay() === 6;
							},
						},
					},
					{
						type: 'numeric',
						numericFormat: {
							pattern: '$ 0,0.00',
						},
					},
				],
				autoWrapRow: true,
				autoWrapCol: true,
			});

			// 导入配置2:设置导入配置属性
			const exportPlugin = hot.getPlugin('exportFile');
			const button = document.querySelector('#export-file');
			button.addEventListener('click', () => {
				exportPlugin.downloadFile('csv', {
					bom: false,
					columnDelimiter: ',',
					columnHeaders: false,
					exportHiddenColumns: true,
					exportHiddenRows: true,
					fileExtension: 'csv',
					filename: 'Handsontable-CSV-file_[YYYY]-[MM]-[DD]',
					mimeType: 'text/csv',
					rowDelimiter: '\r\n',
					rowHeaders: true,
				});
			});
		</script>
	</body>
</html>
  • 演示结果展示(表格数据格式化动态演示)

handsontableJS0002.gif

I. 配置列表默认只读和可排序
const hot = new Handsontable(container, {
    data: data,
    colHeaders: ["年份", "地点1", "地点2", "地点3", "地点4"],
    rowHeaders: true,
    columnSorting: true, // 开启排序
    readOnly: true,
    licenseKey: 'non-commercial-and-evaluation' // 使用非商业和评估许可证
});

效果展示:

image.png

(3)自定义相关

A. 配置表格样式:初始宽度、可拖拉宽度

官方示例地址:Date cell type - JavaScript Data Grid | Handsontable

const hot = new Handsontable(container, {
    data: [
        [ 'A1', 'B1', 'C1', ],
        [ 'A2', 'B2', 'C2', ],
        [ 'A3', 'B3', 'C3', ],
        [ 'A4', 'B4', 'C4', ],
        [ 'A5', 'B5', 'C5', ],
    ],
    width: '100%',
    height: 'auto',
    colHeaders: true,
    rowHeaders: true,
    colWidths: 100, // 定义初始宽度
    manualColumnResize: true, // 可拖拉改变宽度
    autoWrapRow: true,
    autoWrapCol: true,
    licenseKey: 'non-commercial-and-evaluation',
});

展示结果:

handsontableJS-autowidth.gif

B. 自定义表格颜色
<!DOCTYPE html>
<html lang="zh">
	<head>
		<meta charset="UTF-8">
		<meta name="viewport" content="width=device-width, initial-scale=1.0">
		<title>Handsontable 示例</title>

		<script src="https://cdn.bootcdn.net/ajax/libs/handsontable/14.4.0/handsontable.full.js"></script>
		<link href="https://cdn.bootcdn.net/ajax/libs/handsontable/14.4.0/handsontable.full.css" rel="stylesheet">
		<!-- 
		<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/handsontable/dist/handsontable.full.min.css">
		<script src="https://cdn.jsdelivr.net/npm/handsontable/dist/handsontable.full.min.js"></script>
		-->
		<style>
			#example {
				width: 600px;
				height: 300px;
				overflow: hidden;
			}
		</style>
	</head>
	<body>
		<!-- 导入配置1.编写HTML问题 -->
		<div class="example-controls-container">
		  <div class="controls">
		    <button id="export-file">Download CSV</button>
		  </div>
		</div>
		<div id="example"></div>

		<script>
			// 2. 初始化 Handsontable
			const data = [
				{ id: 1, name: 'Ted', isActive: true, color: 'orange', date: '2015-01-01' },
				{ id: 2, name: 'John', isActive: false, color: 'black', date: null },
				{ id: 3, name: 'Al', isActive: true, color: 'red', date: null },
				{ id: 4, name: 'Ben', isActive: false, color: 'blue', date: null },
			];

			const colors = ['yellow', 'red',  'orange', 'green', 'blue',  'gray', 'black', 'white',];
			const yellowRenderer = (instance, td, ...rest) => {
			  Handsontable.renderers.TextRenderer(instance, td, ...rest);
			  td.style.backgroundColor = 'yellow';
			};

			const greenRenderer = (instance, td, ...rest) => {
			  Handsontable.renderers.TextRenderer(instance, td, ...rest);
			  td.style.backgroundColor = 'green';
			};
			const container = document.getElementById('example');
			const hot = new Handsontable(container, {
				data: data,
				colHeaders: true,//["id", "name1", "isActive", "color", "date"],
				rowHeaders: true,
				columns: [
					{ data: 'id', type: 'text' },
					// 'text' is default, you don't actually need to declare it
					{ data: 'name', renderer: yellowRenderer },
					// use default 'text' cell type but overwrite its renderer with yellowRenderer
					{ data: 'isActive', type: 'checkbox' },
					{ data: 'date', type: 'date', dateFormat: 'YYYY-MM-DD HH:mm:ss' },
					{ data: 'color', type: 'autocomplete', source: colors },
				],
				cell: [{ row: 1, col: 0, renderer: greenRenderer }],
				cells(row, col) {
				    if (row === 0 && col === 0) {
						this.renderer = greenRenderer;
						return { renderer: this.renderer };
					}
				
				    return {};
				  },
				autoWrapRow: true,
				autoWrapCol: true,
				height: 'auto',
				licenseKey: 'non-commercial-and-evaluation' // 使用非商业和评估许可证
			});
			
			// 导入配置2:设置导入配置属性
			const exportPlugin = hot.getPlugin('exportFile');
			const button = document.querySelector('#export-file');
			button.addEventListener('click', () => {
			  exportPlugin.downloadFile('csv', {
			    bom: false,
			    columnDelimiter: ',',
			    columnHeaders: false,
			    exportHiddenColumns: true,
			    exportHiddenRows: true,
			    fileExtension: 'csv',
			    filename: 'Handsontable-CSV-file_[YYYY]-[MM]-[DD]',
			    mimeType: 'text/csv',
			    rowDelimiter: '\r\n',
			    rowHeaders: true,
			  });
			});
		</script>
	</body>
</html>

展示样式:

  • 设置指定颜色

image.png

此时点击导出的样式如下:(① 复选框选中与否:true/false; ② 颜色导出失效需要自己设置;)

image.png

(4)事件监听跟踪 Hook

hot.addHook('方法名', (dataInfo, operteType) => {
    console.log(`操作类型:${operteType} ,方法监听的数据 ${dataInfo}`);
});
// 注意:不同的方法名传入的 dataInfo 是不同的,所以这个方法传入的参数值也不近相同,请关注具体的 hook 对应的事件方法函数。

handsontableJS-all-hooks.gif

A. 新增/删除行-触发事件
// 事件1:hook 创建行之后
hot.addHook('afterCreateRow', (row, amount) => {
    console.log(`${amount} row(s) were created, starting at index ${row}`);
});
// 事件3:hook 删除行之后
hot.addHook('afterRemoveRow', (row, amount) => {
    console.log(`${amount} row(s) were removed, starting at index ${row}`);
});
B. 新增/删除列-触发事件
// 事件2:hook 创建列之后
hot.addHook('afterCreateCol', (col, amount) => {
    console.log(`${amount} col(s) were created, starting at index ${col}`);
});
// 事件4:hook 删除列之后
hot.addHook('afterRemoveCol', (col, amount) => {
    console.log(`${amount} col(s) were removed, starting at index ${col}`);
});
C.指定单元格数据变更后触发事件(含A和B操作)
<!DOCTYPE html>
<html>
	<head>
		<meta charset="utf-8">
		<title></title>
		<script src="https://cdn.bootcdn.net/ajax/libs/handsontable/14.4.0/handsontable.full.js"></script>
		<link href="https://cdn.bootcdn.net/ajax/libs/handsontable/14.4.0/handsontable.full.css" rel="stylesheet">
		<!-- 
			教程:https://handsontable.com/docs/javascript-data-grid/events-and-hooks/
		 -->
	</head>
	<body>
		<div id="example"></div>
		
		<script type="text/javascript">
			const container = document.getElementById('example');
			const hot = new Handsontable(container, {
			  data: [
			    ['Tesla', 2017, 'black', 'black'],
			    ['Nissan', 2018, 'blue', 'blue'],
			    ['Chrysler', 2019, 'yellow', 'black'],
			    ['Volvo', 2020, 'yellow', 'gray']
			  ],
			  colHeaders: true,// 开启表头
			  rowHeaders: true,// 开启序号
			  contextMenu: true,// 开启内容编辑
			  height: 'auto',
			  minSpareRows: 1, // 始终保持一空行
			  beforeChange(changes) {
			    lastChange = changes;
			  },
			  autoWrapRow: true,
			  autoWrapCol: true,
			  licenseKey: 'non-commercial-and-evaluation',
			});
			
			// 事件1:hook 创建行之后
			hot.addHook('afterCreateRow', (row, amount) => {
			  console.log(`${amount} row(s) were created, starting at index ${row}`);
			});
			
			// 事件2:hook 创建列之后
			hot.addHook('afterCreateCol', (col, amount) => {
			  console.log(`${amount} col(s) were created, starting at index ${row}`);
			});
			
			// 事件3:hook 删除行之后
			hot.addHook('afterRemoveRow', (row, amount) => {
			  console.log(`${amount} row(s) were removed, starting at index ${row}`);
			});
			
			// 事件4:hook 删除列之后
			hot.addHook('afterRemoveCol', (col, amount) => {
			  console.log(`${amount} col(s) were removed, starting at index ${row}`);
			});
			
			// 事件5:hook 数据改变后
			hot.addHook('afterChange', (allInfo, operateType) => {
				var arrInfo = (allInfo).toString().split(",");
				var rowIndex = arrInfo[0], colIndex = arrInfo[1];
				var changePreValue = arrInfo[2], changedValue = arrInfo[3];
				console.log(`${allInfo}  were changed!改变后的值为:${operateType}`);
				console.log("坐标:", rowIndex, colIndex, "值:",changePreValue, changedValue)
			});
		</script>

	</body>
</html>

测试演示:

  • 演示数据改变后监听事件hook

handsontableJS-key-hooks.gif

附录

  1. 官网地址:Handsontable 是一个 JavaScript 数据网格,外观和感觉都像一个电子表格 - 适用于 React、Angular 和 Vue
  2. HandsonTable 文档地址:handsontable.com/docs/javasc…
  3. HandsonTable 开源地址:GitHub - handsontable/handsontable: JavaScript data grid with a spreadsheet look & feel. Works with React, Angular, and Vue. Supported by the Handsontable team ⚡

(1)注意事项:商用需购买许可证

  • ⚠️HandsonTable 官方注意事项:

image.png


🙏至此,非常感谢阅读🙏

handsontable-main-page-illustration.svg