The vue framework uses xlsx to export excel tables

I have just taken over a project and need to export a table. I have never used it before, so I will record this for future use. This template is suitable for use when modifying table styles. If you just want to simply export directly, you can refer to another article: In vue, use xlsx with FileSaver to export excel tables_Guo Xiaobai's blog-CSDN blog

I benefited a lot from seeing an article: How to use JavaScript to implement pure front-end reading and exporting excel files - Hao Kee's blog

The table data in this project is imported using the table in element ui, so the export is also to directly export the generated table to excel.

Basic template process for table export

1. Download the plug-in first

npm i xlsx
npm i xlsx-style

2. Import in the used page

import XLSX2 from 'xlsx'
import XLSX from 'xlsx-style'

3. Bind the table to be exported and set the column width (the export method for different content is different. Here, the table is directly exported to an excel file, using utils.table_to_sheet, and I will add more after using it)

To determine whether there is data in the table, please look at the third problem encountered below to write it! ! !

var wb = XLSX2.utils.table_to_sheet(document.querySelector('#mytable'))// mytable为表格的id名
      if (!wb['!merges']) {
        this.$message.warning('无法导出:报表无数据')
        return
      }
      // 设置列宽(这里用到列的数量是用来设置不同列的不同宽度的)
      const sum = 1 + this.govMt.length * 7 + 2 // 列的数量,根据自身项目进行数据的更改
      for (var i = 0; i < sum; i++) {
        if (i === sum - 1) {
          wb['!cols'][i] = { wpx: 120 } // 设置列宽,只有最后一列的宽度是不同的
        } else {
          wb['!cols'][i] = { wpx: 60 }
        }
      }

4. Set the style of the cell

for (const key in wb) {
        if (key.indexOf('!') === -1) { // 排除带!的字段,只要单元格字段
          wb[key].s = {
            font: {// 字体设置
              sz: 13,
              bold: false,
              color: {
                rgb: '000000'// 十六进制,不带#
              }
            },
            border: { // 设置边框
              top: { style: 'thin' },
              bottom: { style: 'thin' },
              left: { style: 'thin' },
              right: { style: 'thin' }
            },
            alignment: {// 文字居中 //字体水平居中、垂直居中、自动换行
              horizontal: 'center',
              vertical: 'center',
              wrap_text: true
            }
          }
        }  
      }

The basic settings are like this, and then you can call the following three functions.

var data = this.addRangeBorder(wb['!merges'], wb) // 合并项添加边框
var filedata = this.sheet2blob(data) // 将一个sheet转成最终的excel文件的blob对象
this.openDownloadDialog(filedata, '报表名字.xlsx') // 下载报表

5. Since there are merged cells, it is necessary to add a border to the merged item. For detailed explanation, see four of the problems encountered at the end of the article! !

// 为合并项添加边框
    addRangeBorder(range, ws) {
      const arr = ['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z']
      range.forEach(item => {
        const startColNumber = Number(item.s.r); const endColNumber = Number(item.e.r) // 0-0
        const startRowNumber = Number(item.s.c); const endRowNumber = Number(item.e.c) // 0-16
        const test = ws[arr[startRowNumber] + (startColNumber + 1)] // 合并项第一个单元格中的内容
        for (let col = startColNumber; col <= endColNumber; col++) { // 0-0
          for (let row = startRowNumber; row <= endRowNumber; row++) { // 0-16
            ws[arr[row] + (col + 1)] = test // A1-P1
          }
        }
      })
      return ws
    },

6. Convert a sheet into a blob object of the final excel file, and then download it using URL.createObjectURL

// 将一个sheet转成最终的excel文件的blob对象
sheet2blob(sheet, sheetName) {
      // console.log(sheet, sheetName, 'sheet, sheetName')
      sheetName = sheetName || 'sheet1'
      console.log(sheetName, 'sheetName')
      var workbook = {
        SheetNames: [sheetName],
        Sheets: {}
      }
      workbook.Sheets[sheetName] = sheet // 生成excel的配置项

      var wopts = {
        bookType: 'xlsx', // 要生成的文件类型
        bookSST: false, // 是否生成Shared String Table,官方解释是,如果开启生成速度会下降,但在低版本IOS设备上有更好的兼容性
        type: 'binary'
      }
      var wbout = XLSX.write(workbook, wopts)
      var blob = new Blob([s2ab(wbout)], {
        type: 'application/octet-stream'
      }) // 字符串转ArrayBuffer
      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
    },

Download function using URL.createObjectURL

openDownloadDialog(url, saveName) {
      if (typeof url === 'object' && url instanceof Blob) {
        url = URL.createObjectURL(url) // 创建blob地址
      }
      var aLink = document.createElement('a')
      aLink.href = url
      aLink.download = saveName || '' // HTML5新增的属性,指定保存文件名,可以不要后缀,注意,file:///模式下不会生效
      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)
    }

Problems encountered: 

1. When using xlsx-style to export, the following error may be reported:

Can‘t resolve ‘./cptable‘ in ‘xxx\node_modules_xlsx\xxx

Or appear when npm run serve:

This relative module was not found:  * ./cptable in ./node_modules/xlsx-style/dist/cpexcel.js

There are two solutions:

1. Add the following code to config.js:

module.exports = {
	externals: {
    	'./cptable': 'var cptable'
 	}
}

This code needs to be written into config.js. I found that I do not have this file (I am using vue2.0), so I need to create the vue.config.js file in the root directory and write the following code internally:

module.exports = {
  devServer: {
    port: 80,
    host: '0.0.0.0',
  },
};

At this time, I wrote externals: { './cptable': 'var cptable' } directly into module.exports,

module.exports = {
  devServer: {
    port: 80,
    host: '0.0.0.0',
  },
  externals: {
    './cptable': 'var cptable'
  }
};

 The following error occurred:

ERROR Invalid option

.0ns in vue.config.js: "externals" is not allowed

This means that there is no such field in vue.config.js, so the configured webpack field vue does not map it to vue.config.js. So we have to change the way of quoting:

configureWebpack: { externals: {'./cptable': 'var cptable'} } // 配置webpack的字段。

Then run it again.

2. The second method is to modify  node_modules 中the code, but it is very inconvenient to modify it every time you pull the code npm i.

  Find  ./node_modules/xlsx-style/dist/cpexcel.js the file and modify it manually


var cpt = require('./cpt' + 'able'); 
替换为
var cpt = cptable;

 2. Vue xlsx export table time incomplete problem

Possibility: enter the time column to display the year, month and day, and the hours, minutes and seconds are ignored or displayed individually.####

 Solution:

Add to your code: { raw: true }

var wb = XLSX2.utils.table_to_sheet(document.querySelector('#exportTab'), { raw: true })// exportTab为表格的id名

Rendering:

3. In 3. of the code, the judgment that the report has no data can be flexibly changed.

The following code snippet is used to determine whether there are merged items. If there is no cell merging, this option will not be available, so even if there is data in the table, the code that cannot be exported will always be used, so you can change it from wb A field to judge. For example:  !fullref

If there is a merged item, it can be written as:

 if (!wb['!merges']) {
        this.$message.warning('无法导出:报表无数据')
        return
      }

Can be rewritten as needed:

if (!wb['!fullref']) {
        this.$message.warning('无法导出:报表无数据')
        return
      }

4. Answers to the needs of the combined item function

When our cells are merged cells, if no borders are added to the merged items, the exported table effect will be as shown in the figure:

We found that the border of the merged item is missing. After we call the function to add a border to the merged item, we can solve this problem. The rendering is as follows:

 

Guess you like

Origin blog.csdn.net/qq_46372045/article/details/126779345