handsontable插件的详细使用方法

10,283 阅读6分钟

携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第18天,点击查看活动详情

1. 前言

之前也有写过关于 Handsontable 的文章,但是很片面,由于在项目开发中用了很多次,感觉还不错,功能也很强大,所以打算再做一次更详细的总结。

2. Handsontable介绍

Handsontable 是一个拥有 spreadsheet 特性的数据格子组件,说白了就是像 excel 软件一样,因为其很多特性都和 excel 类似,用户可以不用怎么学习就可以上手操作。Handsontable 采用 JavaScript 脚本而写并且兼容 Vue、React、Angular 及 H5。Handsontable 非常受大家的喜爱,在 github 上有 9k+ 的 star,可以说相当的 nice 了。其官网如下:handsontable.com/docs/7.1.0/…

3. Handsontable的作用及优势

  1. 可以基于其他常规插件来进行修改或扩展。
  2. 可以绑定 json 格式的数据。
  3. 可以处理大量的数据。
  4. 可以处理一些常规操作,比如数据绑定、过滤、排序、读、更新、修改等,还有一些高级操作,比如多列排序,创建单元格样式,对数据进行求和、数据验证、CRUD操作等。
  5. 该组件还支持多种语言,包括中文、日语、德语、西班牙语、法语、葡萄牙语、波兰语和俄语。\

4. Handsontable的使用

这里我主要描述在 Vue 中的使用方法,其他框架中的使用方式就不说了。步骤如下:

4.1. 插件安装

npm i handsontable @handsontable/vue

4.2. 引入资源

// import Handsontable from 'handsontable'
import { HotTable } from '@handsontable/vue'
import '../../../node_modules/handsontable/dist/handsontable.full.css'// 样式
import 'handsontable/languages'// 语言设置

4.3. 注册组件

components: {
    HotTable
},

4.4. 语言设置及隐藏版权文字

hotSettings: {
    language: 'zh-CN', // 语言设置
    licenseKey: 'non-commercial-and-evaluation', // 隐藏版权文字
}

image.png

4.5. 组件调用及数据传递

  • 传递数据的方式有两种:通过 data 属性直接绑定数据,通过设置 settings.data 绑定数据
  • 传递的数据可以是对象数组,也可以是二维数组

方式1 

<template>
  <div class="app-container">
    <!-- 1. 通过给子组件设置 data 属性直接绑定数据 -->
    <HotTable
      ref="hotTableComponent1"
      :data="excelData1"
    />
  </div>
</template>

<script>
export default {
  components: {
    HotTable
  },
  data() {
    return {
      // 二维数组
      excelData1: [
        ['A1', 'B1', 'C1', 'D1', 'E1', 'F1', 'G1', 'H1', 'I1', 'J1'],
        ['A2', 'B2', 'C2', 'D2', 'E2', 'F2', 'G2', 'H2', 'I2', 'J2'],
        ['A3', 'B3', 'C3', 'D3', 'E3', 'F3', 'G3', 'H3', 'I3', 'J3'],
        ['A4', 'B4', 'C4', 'D4', 'E4', 'F4', 'G4', 'H4', 'I4', 'J4'],
        ['A5', 'B5', 'C5', 'D5', 'E5', 'F5', 'G5', 'H5', 'I5', 'J5'],
        ['A6', 'B6', 'C6', 'D6', 'E6', 'F6', 'G6', 'H6', 'I6', 'J6'],
        ['A7', 'B7', 'C7', 'D7', 'E7', 'F7', 'G7', 'H7', 'I7', 'J7'],
        ['A8', 'B8', 'C8', 'D8', 'E8', 'F8', 'G8', 'H8', 'I8', 'J8'],
        ['A9', 'B9', 'C9', 'D9', 'E9', 'F9', 'G9', 'H9', 'I9', 'J9']
      ],
    }
  }
}
</script>

image.png

方式2

<template>
  <div class="app-container">
    <!-- 2. 通过给子组件设置 setting 属性来接收数据 -->
    <HotTable
      ref="hotTableComponent2"
      :settings="hotSettings"
    />
  </div>
</template>

<script>
export default {
  components: {
    HotTable
  },
  data() {
    return {
      // 对象数组
      excelData2: [{
          id: 1,
          flag: 'EUR',
          currencyCode: 'EUR',
          currency: 'Euro',
          level: 0.9033,
          units: 'EUR / USD',
          asOf: '08/19/2019',
          onedChng: 0.0026
        },
        {
          id: 2,
          flag: 'JPY',
          currencyCode: 'JPY',
          currency: 'Japanese Yen',
          level: 124.3870,
          units: 'JPY / USD',
          asOf: '08/19/2019',
          onedChng: 0.0001
        },
        {
          id: 3,
          flag: 'GBP',
          currencyCode: 'GBP',
          currency: 'Pound Sterling',
          level: 0.6396,
          units: 'GBP / USD',
          asOf: '08/19/2019',
          onedChng: 0.00
      }],
        
	  hotSettings: {
        data: []
      }
    }
  },
    
  created() {
    this.hotSettings.data = this.excelData2
  },
}
</script>

image.png

4.6. 设置宽高

hotSettings: {
    width: "auto", // 表格宽度
    height: "300", // 表格高度、设置以后才会出现scroll
}

4.7. 设置单元格右键菜单

这里需要注意的是:

如果 data 绑定的数据是对象数组则无法对列进行操作,如果绑定的是二维数组则不会有这种情况。

hotSettings: {
    contextMenu: {
          items: {
            row_above: {
              name: '上面插入一行'
            },
            row_below: {
              name: '下面插入一行'
            },
            col_left: {
              name: '左侧插入一列'
            },
            col_right: {
              name: '右侧插入一列'
            },
            hsep1: "---------", //提供分隔线
            remove_row: {
              name: '移除本行'
            },
            remove_col: {
              name: '移除本列'
            },
            alignment: {
              name: '对齐方式'
            },
            make_read_only: {
              name: '只读'
            },
            borders: {
              name: '边框'
            },
            copy: {
              name: '复制'
            },
            cut: {
              name: '剪切'
            },
            commentsAddEdit: {
              name: '添加备注',
            },
            commentsRemove: {
              name: '取消备注',
            },
            freeze_column: {
              name: '固定列',
            },
            unfreeze_column: {
              name: '取消列固定',
            },
            hsep2: "---------",
            clear_custom: {
              name: '清空所有单元格数据',
              callback: function() {
                this.clear()
              }
           }
        }
    }   
}

image.png

image.png

4.8. 设置行表头和列表头

设置默认行表头和列表头

hotSettings: {
    rowHeaders: true, // 是否展示行表头,默认是1,2,3等数据,可以['行1','行2']进行自定义展示
    colHeaders: true, // 是否展示列表头,默认(true)是A,B,C等字母,可以['列1','列2']进行自定义展示
}

image.png

自定义行表头和列表头

hotSettings: {
    rowHeaders: ['aaa', 'bbb', 'ccc'], 
    colHeaders: ['ID', 'Country', 'Code', 'Currency', 'Level', 'Units', 'Date', 'Change'],
}

image.png

4.9. 设置初始化行列数、最少行列数、行列最小留白数

注意:必须搭配 columns 使用,否则会报错 image.png

hotSettings: {
    startRows: 5, // 初始化行数,无data属性时生效(该值小于minRows时,以minRows为准)
    startCols: 10, // 初始化列数,无data属性时生效(该值小于minCols时,以minCols为准)
    minRows: 6, // 最少行数(当初始化数据小于该值时,以该值为准)
    minCols: 15, // 最少列数(当初始化数据小于该值时,以该值为准)
    minSpareRows: 1, // 行的最小留白数
    minSpareCols: 2, // 列的最小留白数
    columns: true, // 表格配置,具体每列的type,data等格式设置
}

4.10. 设置表格列(columns) 

	hotSettings: {
    	// 表格配置,具体每列的type,data等格式设置
        columns: [{
          data: 'id', // 映射数据(跟data中的参数名称一致)
          type: 'numeric', // 数据类型
          width: 140, // 列宽
          className: 'htCenter', // 设置表格居中
          readOnly: true // 只读
        },
        {
          data: 'flag'
        },
        {
          data: 'currencyCode',
          type: 'text'
        },
        {
          data: 'currency',
          type: 'text'
        },
        {
          data: 'level',
          type: 'numeric',
          numericFormat: {
            pattern: '0.0000'
          }
        },
        {
          data: 'units',
          type: 'dropdown',
          source: ['1F-中', '2F', '3F', '4F', '5F', '...']
        },
        {
          data: 'asOf',
          type: 'date',
          dateFormat: 'MM/DD/YYYY'
        },
        {
          data: 'onedChng',
          type: 'autocomplete',
          source: ['1F-中', '2F', '3F', '4F', '5F', '...'],
          strict: true, // 值为true,严格匹配
          allowInvalid: true // 值为true时,允许输入值作为匹配内容,只能在strict为true时使用
        }],
	}

image.png

4.11. 设置行高和列宽

hotSettings: {
    rowHeights: 45, // 行高
    colWidths: 180, // 列宽度
    stretchH: 'all', // 自适应列宽,默认值none,last 将最后一列拉伸到最大,all 将所有列均匀拉伸
}

image.png

4.12. 设置单元格文字

hotSettings: {
    // 单元格文字设置
    cell: [
       {row: 0, col: 0, className: "htRight"},
       {row: 1, col: 1, className: "htCenter htMiddle"},
       {row: 2, col: 4, className: "htLeft htBottom"}
    ],
}

image.png

4.13. 表头展示下拉菜单

默认设置

hotSettings: {
    dropdownMenu: true, // 表头展示下拉菜单,默认true||false,也可以自定义展示[]
}

自定义设置

hotSettings: {
    dropdownMenu: ['111', '222', '333'],
}

image.png

4.14. 设置多级表头

hotSettings: {
    nestedRows:true,// 是否开启多级表头
    // 多级表头格式
    nestedHeaders: [
       ['A', {label: 'B', colspan: 6}, 'C'],
       ['D', {label: 'E', colspan: 3}, {label: 'F', colspan: 3}, 'G'],
       ['H', 'I', 'J', 'K', 'L', 'M', 'N', 'R', 'S', 'T']
    ],
}

image.png

4.15. 合并单元格

hotSettings: {
    mergeCells: [ // 合并单元格
       {row: 0, col: 1, rowspan: 1, colspan: 2},  //指定合并,从(1,1)开始行3列3合并成一格
       {row: 1, col: 1, rowspan: 1, colspan: 2},
       {row: 2, col: 1, rowspan: 1, colspan: 2}
    ],
    // mergeCells: this.mergeCells(), // this.mergeCells的内容就是合并单元格信息   
}

image.png

4.16. 其他设置

hotSettings: {
    	className: 'htCenter', // 单元格文字对齐方式(htLeft,htRight,htCenter)
        autoWrapRow: true, // 文字是否自动换行(当没有设置colWidths时生效)
        fixedRowsTop: 0, // 列表内容从上面开始,固定定位的行数(不包含行表头)
        fixedColumnsLeft: 1, // 列表内容从左面开始,固定定位的列数(不包含列表头)
        fillHandle: true, // 是否开启拖拽复制操作(true,false,'horizontal'水平复制,'vertical'垂直复制)
        trimWhitespace: true, // 过滤掉空格
        readonly: false, // 表格是否只读,有true和false两种选择
        formulas: false, // 计算公式,支持公式自动计算
        /** 
        支持的公式:
        任何数字,负数和正数,如浮点数或整数;
        算术运算,如:+,-,/,*,%,^,
        逻辑操作如:AND(),OR(),NOT(),XOR(),
        比较操作,如:=,>,>=,<,<=,<>;
        所有的JavaScript数学常量,如:PI(),E(),LN10(),LN2(),LOG10E(),LOG2E(),SQRT1_2(),SQRT2(),
        错误处理:#DIV/0!,#ERROR!,#VALUE!,#REF!,#NAME?,#N/A,#NUM!,
        字符串操作如:( &连接eq。=-(2&5)将返回-25);
        公式中定义的所有excel 公式 ;
        相对和绝对单元格引用,如:A1,$A1,A$1,$A$1,
        内建变量,如:TRUE,FALSE,NULL,
        自定义变量;
        嵌套函数;
        动态更新。
       */
        comments: true, // 添加注释 ,可以显示注释信息
        filters: true, // 过滤
        manualRowMove: true, // 设置行拖拉
        manualColumnFreeze: true, //手动固定列
        manualColumnMove: true, // 设置列拖拉
        manualRowResize: true, // 自定义行宽
        manualColumnResize: true, // 自定义列高
        preventOverflow: 'vertical', // 防止水平溢出表
        headerTooltips: true, // header 内容过长提示
        tableClassName: ['table01', 'htCenter'],
        dataSchema: { // 对象数组头部设置,预定义对象属性
          car: null,
          year: null,
          chassisColor: null,
          bumperColor: null
        },
        customBorders:[],// 添加边框
        columnSorting: true,// 排序
        allowEmpty: 'false', // 是否允许undefined/null/""为空值判断,为fasle时不包含""
        autoColumnSize: true, // 列根据内容自动变宽
        autoRowSize: false, // 行根据内容自动变化
        copyable: true, // 允许键盘复制
        currentRowClassName: 'my-selectRow', // 给选中行添加自定义class类名
        currentColClassName: 'my-selectCol', // 给选中列添加自定义class类名

        afterRender: this.afterRender(),
        afterValidate: this.afterValidate(),
        beforeChange: this.beforeChange(), // 修改handsontable表格内容前
        afterChange: this.afterChange(), // 修改handsontable表格内容后,自动触发afterChange里的方法
        afterCreateRow: this.afterCreateRow(),
        beforeRemoveRow: this.beforeRemoveRow(),
        afterRemoveRow: this.afterRemoveRow(),
        beforeKeyDown: this.beforeKeyDown(),  
}