有很多小伙伴对SpreadJS没有原生支持格式刷功能而纠结,实际上已经有了非常接近Excel的实现,
本文就来为大家分析一下这个功能是如何实现的,以及提供一个封装好的格式刷功能模块。
一、格式刷的实现:
关于格式刷的实现,需要处理的几个问题点如下:
1、选择边界问题;
当用户选中某个单元格或区域作为源格式区域,再选中一块可能大小不等,甚至重叠的区域,
这时需要怎样处理边界问题,就是我们首先要考虑的。
2、跨sheet问题;
在SpreadJS中,有个copyTo的方法可以实现样式的拷贝,但我们试过就会发现,它不支持跨sheet复制样式,
实际上,SpreadJS提供了一个命令:GC.Spread.Sheets.Commands.clipboardPaste,通过这个命令,
不仅可以实现跨sheet拷贝样式,还支持更加灵活的区域样式拷贝(无需像copyTo一样一对一拷贝range)
3、能否撤销;
在SpreadJS中,所有用户操作都被抽象成一个个的命令(Command),command可以支持撤销、
重做等行为。关于Command的使用方法,参考:
https://www.grapecity.com.cn/blogs/how-to-use-spreadjs-built-in-commands-and-custom-commands
理清楚以上可能遇到的问题,我们就可以着手实现格式刷的功能了.
二、格式刷的实现
1、选择边界处理和跨Sheet实现:
- var targetSheet = me.workbook.getActiveSheet();
- var source = me.getActualRange(me.sourceSheet, me.sourceRange);
- var target = me.getActualRange(targetSheet, targetSheet.getSelections().pop());
- // 仅选一个目标单元格时将按源尺寸复制
- if (target.rowCount === 1 && target.colCount === 1) {
- target.rowCount = Math.min(source.rowCount, targetSheet.getRowCount() - target.row);
- target.colCount = Math.min(source.colCount, targetSheet.getColumnCount() - target.col);
- }
- var targetEndRow = target.row + target.rowCount;
- var targetEndCol = target.col + target.colCount;
复制代码
- getActualRange: function (sheet, range) {
- var isFullRow = range.col === -1;
- var isFullCol = range.row === -1;
- return new GC.Spread.Sheets.Range(isFullCol ? 0 : range.row, isFullRow ? 0 : range.col,
- isFullCol ? sheet.getRowCount() : range.rowCount, isFullRow ? sheet.getColumnCount() : range.colCount);
- }
复制代码
2、clipboardPaste命令调用:
- GC.Spread.Sheets.Commands.clipboardPaste.execute(me.workbook, {
- // 目标sheet的名称
- sheetName: targetSheet.name(),
- // 源sheet
- fromSheet: me.sourceSheet,
- // 源区域
- fromRanges: [new GC.Spread.Sheets.Range(source.row, source.col, copyRows, copyCols)],
- // 目标区域
- pastedRanges: [new GC.Spread.Sheets.Range(row, col, copyRows, copyCols)],
- // 是否剪切
- isCutting: false,
- clipboardText: "",
- // 复制内容(样式)
- pasteOption: GC.Spread.Sheets.ClipboardPasteOptions.formatting
- }, false);
复制代码
三、模块化封装
感谢@GoodGod 同学的分享,对于这个功能模块他做了大量的优化、封装工作。
希望大家多多分享自己的经验,大家相互学习,共同进步!
现在的前端应用越来越讲究模块化,针对这个相对独立的小功能,最好的办法就是把它封装成一个“类”,
在需要的地方将它“实例化”,然后执行调用,管理状态。
对于这个纯功能的案例,模块化相对简单,重写它的prototype即可(当然利用新特性也可以声明class)
参考代码:
- var FormatPainter = function (workbook) {
- this.construct(workbook);
- };
- FormatPainter.prototype = {
- //功能定义
- };
复制代码
完整代码示例参考附件。
|
|