Summary of front-end export table technology

Summary of front-end export table technology

This document is based on various projects and Handan projects that our company needs to export. This document contains two export methods, one is fixed table export and the other is custom table export. The difference is that fixed export can only define the width, not the height. The width and height of the custom table can be freely defined.

There are only a few custom tables exported in the project, and the technical code is complex. Fixed tables are exported as majority and are widely used.

1. Fixed table export

Under the terminal of the VScode project, install two plug-ins

npm install file-saver xlsx -S      导出表格
npm install --save [email protected]      导出表格

Modification: node_modules/xlsx-style/dist/cpexcel.js-----line 807

var cpt = './cptable';

Import it into the page where export is needed

import XLSX2 from "xlsx";
import XLSX from "xlsx-style";

The next html part is the same as the normal el-table, you just need to add a custom id to the el-table tag.

Then set a button, write the click export event, and omit the button code again

 //导出报表---自定义按钮的点击方法
    setExport2Excel() {
    
    
      let fix = document.querySelector(".el-table__fixed");
      let wb;
      var xlsxParam = {
    
     raw: true };
      if (fix) {
    
    
        wb = XLSX2.utils.table_to_book(
          document.querySelector("#自定义id").removeChild(fix),
          xlsxParam
        );
        document.querySelector("#自定义id").appendChild(fix);
      } else {
    
    
        wb = XLSX2.utils.table_to_book(
          document.querySelector("#自定义id"),
          xlsxParam
        );
      }
        
      //宽度,可以把wb.Sheets.Sheet1打印出来,来了解
      //打印后可以发现  "!cols"  属性是一个数组,所以第一行的宽度其实是 i=0  
      //wpx == width px   此为个人理解,也可能这就是正确理解
      //高度无法设置,如果有文档解决高度,希望补全,,修改方法:改源码
      //很难,本人之前试过三种方法,但都失败了,node_modeles改崩了,只能删掉重新npm install
      for (var i = 0; i < 14; i++) {
    
    
        if (i <= 2) {
    
    
          wb.Sheets.Sheet1["!cols"][i] = {
    
     wpx: 100 };
        } else {
    
    
          wb.Sheets.Sheet1["!cols"][i] = {
    
     wpx: 180 };
        }
      }
      for (const key in wb.Sheets.Sheet1) {
    
    
        if (key.indexOf("!") === -1 && wb.Sheets.Sheet1[key].v) {
    
    
          wb.Sheets.Sheet1[key].s = {
    
    
            font: {
    
    
              sz: 13,
              bold: false,
              color: {
    
    
                rgb: "000000",
              },
            },
            alignment: {
    
    
              horizontal: "center",
              vertical: "center",
              wrap_text: true,
            },
            border: {
    
    
              top: {
    
     style: "thin" },
              bottom: {
    
     style: "thin" },
              left: {
    
     style: "thin" },
              right: {
    
     style: "thin" },
            },
          };
        }
      }
      var data = wb.Sheets.Sheet1;
      var filedata = this.sheet2blob(data);
      this.openDownloadDialog(filedata, "文件名-可自定义.xlsx");
    },
    //第二个方法 修饰第一个函数
    sheet2blob(sheet, sheetName) {
    
    
      sheetName = sheetName || "sheet1";
      var workbook = {
    
    
        SheetNames: [sheetName],
        Sheets: {
    
    },
      };
      workbook.Sheets[sheetName] = sheet;
      var wopts = {
    
    
        bookType: "xlsx",
        bookSST: false,
        type: "binary",
      };
      var wbout = XLSX.write(workbook, wopts);
      var blob = new Blob([s2ab(wbout)], {
    
    
        type: "application/octet-stream",
      });
      function s2ab(s) {
    
    
        var buf = new ArrayBuffer(s.length);
        var view = new Uint8Array(buf);
        for (var i = 0; i != s.length; ++i) view[i] = s.charCodeAt(i) & 0xff;
        return buf;
      }
      return blob;
    },
    //第三个方法  修饰第一个函数
    openDownloadDialog(url, saveName) {
    
    
      if (typeof url == "object" && url instanceof Blob) {
    
    
        url = URL.createObjectURL(url);
      }
      var aLink = document.createElement("a");
      aLink.href = url;
      aLink.download = saveName || "";
      var event;
      if (window.MouseEvent) event = new MouseEvent("click");
      else {
    
    
        event = document.createEvent("MouseEvents");
        event.initMouseEvent(
          "click",
          true,
          false,
          window,
          0,
          0,
          0,
          0,
          0,
          false,
          false,
          false,
          false,
          0,
          null
        );
      }
      aLink.dispatchEvent(event);
    },

2. Custom table export (definable width, height and various styles)

This method is based on the requirements raised by Party A when I modified the Handan project, and customized the table style.

General introduction: This method is a simple js export, which has nothing to do with the display of the page. It only requires an export button and click to export.

My application idea: when displaying the page, simply write a set of html code to let Party A see the preview. The real export data and export styles are all in js.

Therefore, omit the html code and introduce the js aspect in detail

Reference link under the project terminal

npm install xlsx-js-style        导出表格(新方法)

in page

import XLSXS from "xlsx-js-style";

js part – I made the export preview into a component, preview it in the pop-up box, click to confirm and it will download.

  data() {
    
    
    return {
    
    
      dialogVisible: false,  //控制弹框是否显示
      row: {
    
    },		//从父级那里拿到的数据
      body: [],		//表格导出的主体内容
      sheet: [],	//表格的内容、样式等各种东西
    };
  },
    showDianlog(row) {
    
    
      this.dialogVisible = true;
      this.row = row;
      this.playdata(row);//渲染表格的方法
    },
playdata(row) {
    
    
    //表格中的数据,常量data,
    //这里需要注意的点:data中每一个对象的属性值需要一样,data[0]中有value0,则data[1-max]中也要有value0、、、、、需要注意占位符,即键值对的 “空键”,即写上“空键”之后在表格中,它仍然独占一格。
    //这里不是正规的实现方法,我是运用此种方法来画出 我想要的表格样式,如果想要导出表格的数据,直接赋值即可。
    //当然如果想要导出固定表格的数据,用上面的第一种方法即可。
    //此种方法,主要是画出自己或者甲方需要的表格,下面的两行,就是画出来的“假”表头
    //额外说明  "\n" =  换行     "    " =  缩进
    const data = [
        {
    
    
          value0: "报修工单",
          value1: "",
          value2: "",
          value3: "",
          value4: "",
          value5: "档案编号:",
          value6: row.file_no,
        },
        {
    
    
          value0: "设备名称",
          value1: "设备编号",
          value2: "设备地点",
          value3: "报修人",
          value4: "报修时间",
          value5: "维修时效",
          value6: "",
        },
        {
    
    
          value0: row.dev_name,
          value1: row.dev_no,
          value2: row.dev_position,
          value3: row.author,
          value4: row.create_at,
          value5: row.finish_at,
          value6: "",
        },
        ......
    ]//不知道是什么,不过这么写就行
    this.body = data.map((x) => [
        x.value0,
        x.value1,
        x.value2,
        x.value3,
        x.value4,
        x.value5,
        x.value6,
    ]);
    
    //第一行真正的表头
     const header = [
        // 第一行,需要样式,则数组中元素为对象,进行定义样式。
        [
          {
    
    
            v: "附件:",
            t: "s",
            s: {
    
    
              // font 字体属性
              font: {
    
    
                bold: false,
                sz: 12,
                name: "宋体",
              },
              // alignment 对齐方式
              alignment: {
    
    
                vertical: "top", // 垂直居中
                horizontal: "left", // 水平居中
              },
              // border: {
    
    
              //   top: { style: "thin" },
              //   bottom: { style: "thin" },
              //   left: { style: "thin" },
              //   right: { style: "thin" },
              // },
              // fill 颜色填充属性
              // fill: {
    
    
              //   fgColor: { rgb: "ffffff" },
              // },
            },
          },
        ],
      ];
    
    this.body.unshift(...header);  //加入数组的第一项
    this.sheet = XLSXS.utils.aoa_to_sheet(this.body);
    
    //合并单元格:数组,其中每一个对象都需要独立理解
    //s=开始(start)  e=结束(end)  r=行(row)  l=列(clounm)
    //以第一的对象来解释:第4行的第1个标签合并到第4行的第6个单元格
      const merges = [
        {
    
     s: {
    
     r: 4, c: 0 }, e: {
    
     r: 4, c: 6 } },
        {
    
     s: {
    
     r: 5, c: 0 }, e: {
    
     r: 5, c: 6 } },
        {
    
     s: {
    
     r: 8, c: 0 }, e: {
    
     r: 8, c: 6 } },
        {
    
     s: {
    
     r: 9, c: 0 }, e: {
    
     r: 9, c: 6 } },
      ];
      this.sheet["!merges"] = merges; // 添加到sheet中
    
    //列宽,每一列的长度,wpx = width px
      const cols = [
        {
    
     wpx: 70 },
        {
    
     wpx: 70 },
        {
    
     wpx: 75 },
        {
    
     wpx: 70 },
        {
    
     wpx: 75 },
        {
    
     wpx: 75 },
        {
    
     wpx: 75 },
      ];
      this.sheet["!cols"] = cols; // 添加到sheet中
    
    //行高,每一行的高度  hpx = height px
      const rows = [
        {
    
     hpx: 40 },
        {
    
     hpx: 20 },
        {
    
     hpx: 40 },
        {
    
     hpx: 40 },
        {
    
     hpx: 150 },
        {
    
     hpx: 40 },
        {
    
     hpx: 40 },
        {
    
     hpx: 40 },
        {
    
     hpx: 150 },
        {
    
     hpx: 120 },
      ];
      this.sheet["!rows"] = rows; // 添加到sheet中
    
    //编辑特定的某个单元格样式
    //举例
    //后面会把各种属性值都列举出来
      this.sheet["A2"].s = {
    
    
        font: {
    
    
          bold: false,
          sz: 12,
          name: "宋体",
        },
        alignment: {
    
    
          vertical: "center", // 垂直居中
          horizontal: "left", // 水平居中
        },
      };
}
style properties subproperty value
fill patternType "solid" or "none"
fgColor COLOR_SPEC
bgColor COLOR_SPEC
font name "Calibri" // default
sz "11" // font size in points
color COLOR_SPEC
bold trueorfalse
underline trueorfalse
italic trueorfalse
strike trueorfalse
outline trueorfalse
shadow trueorfalse
vertAlign trueorfalse
numFmt "0" // integer index to built in formats, see StyleBuilder.SSF property
"0.00%" // string matching a built-in format, see StyleBuilder.SSF
"0.0%" // string specifying a custom format
"0.00%;\\(0.00%\\);\\-;@" // string specifying a custom format, escaping special characters
"m/dd/yy" // string a date format using Excel’s format notation
alignment vertical "bottom" or "center" or "top"
horizontal "bottom" or "center" or "top"
wrapText true or false
readingOrder 2 // for right-to-left
textRotation Number from 0 to 180 or 255 (default is 0)
90 is rotated up 90 degrees
45 is rotated up 45 degrees
135 is rotated down 45 degrees
180 is rotated down 180 degrees
255 is special, aligned vertically
border top { style: BORDER_STYLE, color: COLOR_SPEC }
bottom { style: BORDER_STYLE, color: COLOR_SPEC }
left { style: BORDER_STYLE, color: COLOR_SPEC }
right { style: BORDER_STYLE, color: COLOR_SPEC }
diagonal { style: BORDER_STYLE, color: COLOR_SPEC }
diagonalUp trueorfalse
diagonalDown trueorfalse

The code above needs to be declared in the created hook function,

Click the download button below

    setExport2Excel() {
    
    
      const workbook = XLSXS.utils.book_new(); // 创建虚拟的 workbook
      XLSXS.utils.book_append_sheet(workbook, this.sheet, "sheet名称"); // 向 workbook 中添加 sheet
      XLSXS.writeFile(workbook, this.row.file_no + ".xlsx"); // 导出 workbook
    },

Guess you like

Origin blog.csdn.net/qq_46207981/article/details/129552840