luckysheet的一点使用心得

如何使用

DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Titletitle>
    <style>
        #luckysheet {
            width: 100%;
            height: 600px;
        }
    style>

    <link rel='stylesheet' href='https://cdn.jsdelivr.net/npm/luckysheet/dist/plugins/css/pluginsCss.css' />
    <link rel='stylesheet' href='https://cdn.jsdelivr.net/npm/luckysheet/dist/plugins/plugins.css' />
    <link rel='stylesheet' href='https://cdn.jsdelivr.net/npm/luckysheet/dist/css/luckysheet.css' />
    <link rel='stylesheet' href='https://cdn.jsdelivr.net/npm/luckysheet/dist/assets/iconfont/iconfont.css' />
    <script src="https://cdn.jsdelivr.net/npm/luckysheet/dist/plugins/js/plugin.js">script>
    <script src="https://cdn.jsdelivr.net/npm/luckysheet/dist/luckysheet.umd.js">script>
head>

<body>
	<div id="luckysheet">div>
body>

<script>
 luckysheet.create()
script>

luckysheet的一点使用心得_第1张图片


初始化时写入默认数据

   luckysheet.create({
        container: 'luckysheet', // luckysheet为容器id
        lang: 'zh',              // 设定表格语言
        data: [
            {
                name: '工作表名称',
                row: 30,                 // 行数
                column: 30,              // 列数
                // defaultRowHeight: 19, // 自定义行高
                // defaultColWidth: 73,  // 自定义列宽
                // 初始化使用的单元格数据
                celldata: [
                    {
                        r: '0',
                        c: '1',
                        v: {
                            m: 'img \r\n 555 123',
                            v: 'img \r\n 555 123',
                            fc: '#ff0000',
                            tb: 2,  // 内容超出自动换行
                        }
                    },
                    {
                        r: '0',
                        c: '3',
                        v: {
                            m: 'rq',
                            v: 'rq',
                        }
                    },
                    {
                        r: '0',
                        c: '5',
                        v: {
                            m: 'rq',
                            v: 'rq',
                        }
                    },
                    {
                        r: '3',
                        c: '5',
                        v: {
                            m: 'img',
                            v: 'img',
                        }
                    }
                ]
            }
        ],
    });


根据内容查找格子

function search() {
    console.log(luckysheet.find("rq")); // 返回数组
}

设置所有单元格文字自动换行

// 设置所有单元格自动换行
// 需要先设置换行,再写入值,才有效果。先设置值,再设置换行,没有效果
function setTextWrap() {
    const rowNum = allSheetData.length;    // 表格行数
    const colNum = allSheetData[0].length; // 表格列数

    for (let _row = 0; _row < rowNum; _row++) {
        for (let _col = 0; _col < colNum; _col++) {
            luckysheet.setCellValue(_row, _col, {
                tb: 2,
                // bg: "#FF0000"
            }, {
                // 是否刷新界面,默认true,多单元格赋值时控制节流,前面单元格置为false,最后一个单一个置为true
                isRefresh: _row === rowNum - 1 && _col === colNum - 1,
                success: () => {}
            })
        }
    }
}

替换格子的内容

// 替换格子内容
function replace() {
    range = luckysheet.getRange(); // 存放原来的选中区域

    luckysheet.find("rq").forEach(({ row, column }, index, arr) => {
        luckysheet.setCellValue(row, column, {
              m: '2020- \r\n 星期日',
              v: '2020- \r\n 星期日',
              tb: 2,
              isRefresh: true, // 是否刷新界面,默认true,多单元格赋值时控制节流,前面单元格置为false,最后一个单一个置为true
        }, {
            success: () => {
                // 先选中
                luckysheet.setRangeShow({ row:[row], column:[column] });

                // 再进入编辑模式,让换行生效
                luckysheet.enterEditMode({
                    success: () => {
                        if (index === arr.length - 1) {
                            // 退出编辑模式
                            luckysheet.exitEditMode();

                            // 选中替换前的选区
                            luckysheet.setRangeShow({ row: range[0].row, column: range[0].column })
                        }
                    }
                });
            }
        });
    })
}

插入图片

function insertImage() {
/** @desc mc是合并单元格后的数据 */
luckysheet.find("img").forEach(({ row, column, mc }) => {
    const cellWidth = luckysheet.getColumnWidth([column])[column];
    const cellHeight = luckysheet.getRowHeight([row])[row];

    let img = new Image();
    img.src = './demo.jpg';
    img.width = cellWidth * (mc?.cs || 1);
    img.height = cellHeight * (mc?.rs || 1);

    img.onload = function () {
        let canvas = document.createElement('canvas');
        canvas.width = this.width;
        canvas.height = this.height;
        const context = canvas.getContext('2d');
        context.drawImage(img, 0, 0, this.width, this.height);
        const dataUrl = canvas.toDataURL("image/png");

        luckysheet.clearCell(row, column);
        luckysheet.insertImage(dataUrl, {
            order: 0,
            rowIndex: row,
            colIndex: column,
            success: () => {
                // 【源代码】src/controllers/imageCtrl.js:677 fixme  插入图片 宽/高内部设置为400
            }
        });
    }
})
}

源代码中,插入图片时,图片的默认展示尺寸为宽/高400,需要点击图片,选择恢复原图,才是图片的真实宽高。

我的需求时,插入的图片根据格子的大小,自动填满整个格子。所以我把src/controllers/imageCtrl.js:677的代码改了,打包后,项目引用本地文件

luckysheet的一点使用心得_第2张图片

<link rel='stylesheet' href='https://cdn.jsdelivr.net/npm/luckysheet/dist/plugins/css/pluginsCss.css' />
<link rel='stylesheet' href='https://cdn.jsdelivr.net/npm/luckysheet/dist/plugins/plugins.css' />
<link rel='stylesheet' href='https://cdn.jsdelivr.net/npm/luckysheet/dist/css/luckysheet.css' />
<link rel='stylesheet' href='https://cdn.jsdelivr.net/npm/luckysheet/dist/assets/iconfont/iconfont.css' />


<script src="plugin.js">script>
<script src="luckysheet.umd.js">script>

获取表格的配置和数据

function getConfig() {
    console.log(luckysheet.getAllSheets());
}

文字换行不生效

初始化数据或者用方法修改内容,内容中含有换行符,页面的格子没有换行,需要双击格子,进入编辑模式,换行才会生效。

我的解决方法:表格创建后,查找含有换行符的格子,逐个进入编辑模式,然后退出编辑模式

luckysheet.create({
        container: 'luckysheet', // luckysheet为容器id
        lang: 'zh',              // 设定表格语言
        data: [
            {
                name: '工作表名称',
                row: 30,                 // 行数
                column: 30,              // 列数
                // defaultRowHeight: 19, // 自定义行高
                // defaultColWidth: 73,  // 自定义列宽
                // 初始化使用的单元格数据
                celldata: [
                    {
                        r: '0',
                        c: '1',
                        v: {
                            m: 'img \r\n 555 123',
                            v: 'img \r\n 555 123',
                            fc: '#ff0000',
                            tb: 2, // 内容超出自动换行
                        }
                    },
                    {
                        r: '0',
                        c: '3',
                        v: {
                            m: 'rq',
                            v: 'rq',
                        }
                    },
                    {
                        r: '0',
                        c: '5',
                        v: {
                            m: 'rq',
                            v: 'rq',
                        }
                    },
                    {
                        r: '3',
                        c: '5',
                        v: {
                            m: 'img',
                            v: 'img',
                        }
                    }
                ]
            }
        ],
        hook: {
            // 表格创建之后触发
            workbookCreateAfter:function(allConfig){
                console.log(allConfig);

                luckysheet.find("\n").forEach(({ row, column }, index, arr) => {
                    luckysheet.setRangeShow({ row:[row], column:[column] }, {
                        success: () => {
                            // 进入编辑模式,让换行生效
                            luckysheet.enterEditMode({
                                success: () => {
                                    if (index === arr.length - 1) {
                                        // 退出编辑模式
                                        luckysheet.exitEditMode();

                                        // 选中第一个格子
                                        luckysheet.setRangeShow({ row:[0], column:[0] }, {
                                            show: false, // 选中状态不要高亮
                                        })
                                    }
                                }
                            });
                        }
                    })
                });

                allSheetData = luckysheet.getSheetData();
            }
        }
    });

根据后端数据填写表格

// 写入表格数据
    setData () {
      const { excelData } = this;
      let setCount = 0;

      Object.keys(excelData).forEach((key) => {
        luckysheet.find(key, {
          type: 'v',            // 查找原始值,替换显示值,后期可以重复更新
          // isWholeWord: true, // 整词匹配,避免匹配到其它的格子 有合并格子会报错
        })
          .filter(fItem => fItem.v === key) // 因为整词匹配遇到合并格子会报错,所以在结果里过滤原始值全等的项
          .forEach(({ row, column }) => {

          setCount += 1

          if (excelData[key].startsWith('http')) {
            const img = new Image()
            img.setAttribute('crossOrigin', 'anonymous')
            img.src = excelData[key]
            img.width = '200'
            img.height = '200'

            img.onload = () => {
              let canvas = document.createElement('canvas')
              canvas.width = img.width
              canvas.height = img.height
              const context = canvas.getContext('2d')
              context.drawImage(img, 0, 0, img.width, img.height)
              const quality = 0.8
              const dataUrl = canvas.toDataURL('image/png', quality)

              luckysheet.setCellValue(row, column, { m: '' }, {
                success: () => {
                  luckysheet.insertImage(dataUrl, {
                    rowIndex: row,
                    colIndex: column,
                    success: () => {
                      setCount--
                      this.getShot(setCount)
                    }
                  })
                }
              });
            }

            return
          }

          luckysheet.setCellValue(row, column, {
            m: excelData[key], // 设置显示值
            v: excelData[key], // 设置显示值

            // 设置为纯文本模式,避免设置日期 e.g. 2020-08-29时,编辑模式弹出个日期选择器
            ct: {
              fa: "@",
              t: "s"
            },
            // tb: 2,   // 文本超出格子,自动换行。自动编辑模式撑开高度时,高度会变得很高
            ht: 1,      // 文字左对齐
          }, {
            success: () => {
              // 先选中
              luckysheet.setRangeShow({ row:[row], column:[column] });

              // 再进入编辑模式,让换行生效,默认值v才能撑开格子
              luckysheet.enterEditMode({
                success: () => {
                  // 退出编辑模式
                  luckysheet.exitEditMode();

                  setCount--
                  this.getShot(setCount)
                }
              });
            }
          })
        })
      })
    },

    /**
     * 获取表格图片
     * @params setCount 正在进行赋值操作的格子数
     * */
    getShot(setCount) {
      if (setCount > 0) {
        return;
      }

      const sheetData = luckysheet.getSheetData();
      luckysheet.setRangeShow({ row: [0, sheetData.length - 1], column: [0, sheetData[0].length - 1] }, {
          success: () => {
            const shot = luckysheet.getScreenshot({ row: [0, sheetData.length - 1], column: [0, sheetData[0].length - 1] });

            this.url = shot
          }
        }
      )
    },

表格截图(没有插入图片)

要选中表格区域,才能截图
正常情况,截图里没有出现你插入的图片

 const sheetData = luckysheet.getSheetData();
      luckysheet.setRangeShow({ row: [0, sheetData.length - 1], column: [0, sheetData[0].length - 1] }, {
          success: () => {
            const shot = luckysheet.getScreenshot({ row: [0, sheetData.length - 1], column: [0, sheetData[0].length - 1] });

            this.url = shot
          }
        }
      )

表格截图(有插入图片)

先把能截出来的底图画在canvas上,然后遍历图片信息,再上一步的基础上把图片加上去
我遇到的问题是,图片位置不能对在格子上,会出现偏移,无解

 	// 表格截图
    // 获取表格图片
    function getShot() {
        luckysheet.setRangeShow({ row: [0, allSheetData.length - 1], column: [0, allSheetData[0].length - 1] }, {
                success: () => {
                    const shot = luckysheet.getScreenshot({ row: [0, allSheetData.length - 1], column: [0, allSheetData[0].length - 1] });
                    let { ch_width, rh_height, images = {} } = luckysheet.getAllSheets()[0];

                    if (Object.keys(images).length) {
                        let canvas = document.createElement('canvas');
                        canvas.width = ch_width;
                        canvas.height = rh_height;
                        const context = canvas.getContext('2d');

                        const img = new Image();
                        img.src = shot;
                        img.width = ch_width;
                        img.height = rh_height;

                        img.onload = function () {
                            context.drawImage(img, 0, 0, this.width, this.height);
                            const dataUrl = canvas.toDataURL("image/png");

                            Object.values(images).forEach((image, index, arr) => {
                                const img = new Image();
                                img.src = image.src;
                                img.width = image.originWidth;
                                img.height = image.originHeight;

                                img.onload = function () {
                                    context.drawImage(img, image.default.left, image.default.top, this.width, this.height);

                                    if (index === arr.length - 1) {
                                        const dataUrl = canvas.toDataURL("image/png");
                                    }
                                }
                            })
                        };
                    }
                }
            }
        )
    }

打印

import printJS from "print-js";
   
// 打印
    handlePrint() {
      if (!this.url) {
        console.error('没有图片');
        return;
      }

      printJS(
        {
          printable: this.url,
          type: 'image',
          documentTitle: '表格名称',
          style: '@page{size:auto;margin: 0cm 1cm 0cm 1cm;}' // 去除页眉页脚
        }
      )
    },

根据后端配置,初始化表格

    // 加载表格
    loadSheet() {
      luckysheet.create({
        ...this.sheetOptions, // 后端返回的一些通用配置、格子数据
        showtoolbarConfig: {},
        enableAddRow: false,
        enableAddBackTop: false,
      })

      // 获取表格数据,然后通过上面表格初始化填上的key,进行替换操作
      this.getExcelData();
    },

导出PDF

主要是对上面截图的导出

import jsPDF from 'jspdf';
import html2canvas from 'html2canvas'

 // 导出表格数据
    async exportTableData() {
      this.$message('导出中...');

      setTimeout(() => {
        const element = document.querySelector(".el-image > img");
        // window.pageYOffset = 0;
        // document.documentElement.scrollTop = 0
        // document.body.scrollTop = 0
        html2canvas(element,{
          // height: node.offsetHeight,
          allowTaint: true,
          // allowTaint: true,
          logging:true,
          scale: 2 // 提升画面质量,但是会增加文件大小
        }).then(function (canvas) {
          var contentWidth = canvas.width;
          var contentHeight = canvas.height;
          //一页pdf显示html页面生成的canvas高度;
          var pageHeight = contentWidth / 592.28 * 841.89;
          //未生成pdf的html页面高度
          var leftHeight = contentHeight;
          //页面偏移
          var position = 0;
          //a4纸的尺寸[595.28,841.89],html页面生成的canvas在pdf中图片的宽高
          var imgWidth = 595.28;
          var imgHeight = 592.28 / contentWidth * contentHeight;

          var pageData = canvas.toDataURL('image/jpeg', 1.0);

          var pdf = new jsPDF('', 'pt', 'a4');

          //有两个高度需要区分,一个是html页面的实际高度,和生成pdf的页面高度(841.89)
          //当内容未超过pdf一页显示的范围,无需分页
          if (leftHeight < pageHeight) {
            pdf.addImage(pageData, 'JPEG', 0, 0, imgWidth, imgHeight);
          } else {    // 分页
            while (leftHeight > 0) {
              pdf.addImage(pageData, 'JPEG', 0, position, imgWidth, imgHeight)
              leftHeight -= pageHeight;
              position -= 841.89;
              //避免添加空白页
              if (leftHeight > 0) {
                pdf.addPage();
              }
            }
          }
          pdf.setFont('simsun');
          pdf.save('记录.pdf');
        });
      }, 1000)
    },

隐藏表格,获取截图

需要把结构渲染出来,然后设置为不可见,不然我手动触发格子的编辑模式来撑开格子位置就不能生效

    <div class="imgBox" v-else  v-show="true">
        <el-image
          :src="url"
          :preview-src-list="[url]"
        />
      div>

      
      <div class="sheet-container" style="z-index: -1">
        <div class="print_content" id="luckysheet" />
      div>
   .sheet-container {
      width: 100%;
      height: 500px;
      position: relative;

      .print_content {
        width: 100%;
        height: 100%;
      }
    }

    .imgBox {
      height: calc(100% - 80px);
      overflow: auto;
    }

测试相关代码

【github】


实际使用出现的问题

换行生效后,格子高度被撑高

表格已经设置了行高,进入编辑模式,让换行生效后退出,格子高度会变高


	originSheetOptions: {}, // 表格信息和配置,存储第一次的配置,不会改变
    sheetOptions: {},       // 表格信息和配置,操作表格,里面的数据会变

	// opt是后台接口返回的表格数据和配置
	// 换行后格子高度会变化,数据也会被修改,所以要把原始的配置存起来,用来做修复
	// cloneDeep是深拷贝,避免数据污染
	this.originSheetOptions = cloneDeep(opt);
    this.sheetOptions = cloneDeep(opt);

	// 加载表格
    loadSheet() {
      luckysheet.create({
        ...this.sheetOptions,
        // showtoolbarConfig: {},
        // enableAddRow: false,
        // enableAddBackTop: false,
      })

	  // 获取真实数据,替换表格的占位内容
      this.getExcelData();
    }
	
	// 一系列操作,如,替换占位内容,插入图片等

	// 重新设置行高,修复格子高度变高的问题
    fixRowHeight() {
      const rowHeight = this.originSheetOptions.data[0].config.rowlen;

      return new Promise(resolve => {
        luckysheet.setRowHeight(rowHeight, {
          success: () => {
            resolve()
          }
        });
      })
    },

换行后,文字的样式丢失

文字样式如:字体大小,字体颜色等

 const findItems = luckysheet.find(key, {
          type: 'v',            // 查找原始值,替换显示值,后期可以重复更新
          // isWholeWord: true, // 整词匹配,避免匹配到其它的格子 有合并格子会报错
        }).filter(fItem => fItem.v === key); // 因为整词匹配遇到合并格子会报错,所以在结果里过滤原始值全等的项



 findItems.forEach(({ row, column, ...args }, cellIndex, cellArr) => {}



 luckysheet.setCellValue(row, column, {
            m: excelData[key], // 设置显示值
            v: excelData[key], // 设置原始值
          }, {
            success: () => {
              // 先选中
              luckysheet.setRangeShow({ row:[row], column:[column] });

              // 再进入编辑模式,让换行生效,默认值v才能撑开格子
              luckysheet.enterEditMode({
                success: () => {
                  // 退出编辑模式
                  luckysheet.exitEditMode({
                    success: () => {

                      // 当setCellValue的值存在换行符,同时用编辑模式来让换行生效后,所在格子的v、m属性会被删除,后续无法通过luckysheet.find找到格子
                      // v的值会被移动到 格子.ct.s[0].v 里面
                      // 和文字相关的属性如ff(字体),还在原来的位置,如格子.ff,造成文字相关的样式丢失,所以需要把格子.文字相关样式 移动到 格子.ct.s[0]里面
                      const rangeValue = luckysheet.getRangeValuesWithFlatte();
                      if (rangeValue[0].ct.s) {
                        const { ff, fs, fc, bl, it, cl, un } = args;

                        rangeValue[0].ct.s[0] = {
                          ...rangeValue[0].ct.s[0],
                          ff, // 字体
                          fs, // 字体大小
                          fc, // 字体颜色
                          bl, // 粗体
                          it, // 斜体
                          cl, // 删除线
                          un, // 下划线
                        }
                      }

                      ...
                    }
                  });
                }
              });
            }
          })

获取的截图有点模糊

// 修改表格配置
opt.devicePixelRatio = 4; // 避免导出图片模糊

插入单元格的图片位置偏移

// 修改表格配置
opt.zoomRatio = 1; // 避免插入图片偏移

出现的原因是
保存配置时,表格是缩放到80%的
重新加载表格时,表格读取配置,显示为80%
这时往指定单元格插入图片时,就会出现偏移
需要在加载表格前,把缩放比例配置设为100%,再进行插入

你可能感兴趣的:(前端,前端)