vue实现通用导出(excel,csv, pdf文件)组件 前端导出

后台管理项目中经常使用文件导入导出,故封装了一个通用table的导出组件的实现

vue实现通用导出(excel,csv, pdf文件)组件 前端导出_第1张图片

思路 使用 Dropdown 控件选择导出类型 触发导出
 
导出的table 数据类型
 1 tableColumns: [
 2         {
 3           title: '序号',
 4           key: 'Ordinal',
 5           align: 'center'
 6         },
 7         {
 8           title: '产品编号',
 9           key: 'ProductNo',
10           align: 'left'
11         }
12 ]
13 tableData: [{Ordinal:1,ProductNo:'1234',ProductDesc:'1232222'}]

 

导出文件大部分情况下是后端处理,有时候我们只需要js处理 该怎么做呢?
1.导出CSV
     首先实现导出CSV格式 
    拼接 csv格式其实就是个纯文本文件,中间使用逗号或者换行符进行拼接
    这里使用 json2cvs这个包 需要npm 安装 npm install json2csv  -s
    下载方式 
        IE浏览器 不支持a标签进行下载,会打开url 故
        对于微软系浏览器(IE和Edge)和非微软系列浏览器采用两种不同的方式进行下载
        IE和Edge 采用了  navigator.msSaveBlob 方法 此方法为IE10及以上特有,IE10以下勿采用
        非微软浏览器 使用a标签的click事件进行下载
 关键代码
 1 try {
 2         const result = json2csv.parse(rows, {
 3           fields: fields,
 4           excelStrings: true
 5         });
 6         if (this.MyBrowserIsIE()) {
 7           // IE10以及Edge浏览器
 8           var BOM = "\uFEFF";
 9                   // 文件转Blob格式
10           var csvData = new Blob([BOM + result], { type: "text/csv" });
11           navigator.msSaveBlob(csvData, `${fileName}.csv`);
12         } else {
13           let csvContent = "data:text/csv;charset=utf-8,\uFEFF" + result;
14           // 非ie 浏览器
15           this.createDownLoadClick(csvContent, `${fileName}.csv`);
16         }
17       } catch (err) {
18         alert(err);
19       }
1   //创建a标签下载
2     createDownLoadClick(content, fileName) {
3       const link = document.createElement("a");
4       link.href = encodeURI(content);
5       link.download = fileName;
6       document.body.appendChild(link);
7       link.click();
8       document.body.removeChild(link);
9     },
 1 // 判断是否IE浏览器
 2     MyBrowserIsIE() {
 3       let isIE = false;
 4       if (
 5         navigator.userAgent.indexOf("compatible") > -1 &&
 6         navigator.userAgent.indexOf("MSIE") > -1
 7       ) {
 8         // ie浏览器
 9         isIE = true;
10       }
11       if (navigator.userAgent.indexOf("Trident") > -1) {
12         // edge 浏览器
13         isIE = true;
14       }
15       return isIE;
16     },
2.导出Excel类型文件
 
  导出excel借鉴了iview-admin 自带的excel操作js(需要npm安装 xlsx)npm install xlsx -s
需要导出的地方调用excel.export_array_to_excel函数即可
1 const param = {
2 title: titles,
3 key: keys,
4 data: this.exportData,
5 autoWidth: true,
6 filename: this.exportFileName
7 };
8 excel.export_array_to_excel(param);

完整excel操作js代码如下 excel.js

  1 /* eslint-disable */
  2 import XLSX from 'xlsx';
  3 
  4 function auto_width(ws, data) {
  5   /*set worksheet max width per col*/
  6   const colWidth = data.map(row => row.map(val => {
  7     /*if null/undefined*/
  8     if (val == null) {
  9       return {
 10         'wch': 10
 11       };
 12     }
 13     /*if chinese*/
 14     else if (val.toString().charCodeAt(0) > 255) {
 15       return {
 16         'wch': val.toString().length * 2
 17       };
 18     } else {
 19       return {
 20         'wch': val.toString().length
 21       };
 22     }
 23   }))
 24   /*start in the first row*/
 25   let result = colWidth[0];
 26   for (let i = 1; i < colWidth.length; i++) {
 27     for (let j = 0; j < colWidth[i].length; j++) {
 28       if (result[j]['wch'] < colWidth[i][j]['wch']) {
 29         result[j]['wch'] = colWidth[i][j]['wch'];
 30       }
 31     }
 32   }
 33   ws['!cols'] = result;
 34 }
 35 
 36 function json_to_array(key, jsonData) {
 37   return jsonData.map(v => key.map(j => {
 38     return v[j]
 39   }));
 40 }
 41 
 42 // fix data,return string
 43 function fixdata(data) {
 44   let o = ''
 45   let l = 0
 46   const w = 10240
 47   for (; l < data.byteLength / w; ++l) o += String.fromCharCode.apply(null, new Uint8Array(data.slice(l * w, l * w + w)))
 48   o += String.fromCharCode.apply(null, new Uint8Array(data.slice(l * w)))
 49   return o
 50 }
 51 
 52 // get head from excel file,return array
 53 function get_header_row(sheet) {
 54   const headers = []
 55   const range = XLSX.utils.decode_range(sheet['!ref'])
 56   let C
 57   const R = range.s.r /* start in the first row */
 58   for (C = range.s.c; C <= range.e.c; ++C) { /* walk every column in the range */
 59     var cell = sheet[XLSX.utils.encode_cell({
 60       c: C,
 61       r: R
 62     })] /* find the cell in the first row */
 63     var hdr = 'UNKNOWN ' + C // <-- replace with your desired default
 64     if (cell && cell.t) hdr = XLSX.utils.format_cell(cell)
 65     headers.push(hdr)
 66   }
 67   return headers
 68 }
 69 
 70 export const export_table_to_excel = (id, filename) => {
 71   const table = document.getElementById(id);
 72   const wb = XLSX.utils.table_to_book(table);
 73   XLSX.writeFile(wb, filename);
 74 
 75   /* the second way */
 76   // const table = document.getElementById(id);
 77   // const wb = XLSX.utils.book_new();
 78   // const ws = XLSX.utils.table_to_sheet(table);
 79   // XLSX.utils.book_append_sheet(wb, ws, filename);
 80   // XLSX.writeFile(wb, filename);
 81 }
 82 
 83 export const export_json_to_excel = ({
 84   data,
 85   key,
 86   title,
 87   filename,
 88   autoWidth
 89 }) => {
 90   const wb = XLSX.utils.book_new();
 91   data.unshift(title);
 92   const ws = XLSX.utils.json_to_sheet(data, {
 93     header: key,
 94     skipHeader: true
 95   });
 96   if (autoWidth) {
 97     const arr = json_to_array(key, data);
 98     auto_width(ws, arr);
 99   }
100   XLSX.utils.book_append_sheet(wb, ws, filename);
101   XLSX.writeFile(wb, filename + '.xlsx');
102 }
103 
104 // 导出不带有汉字标题的execel内容
105 export const export_array_to_excel = ({
106   key,
107   data,
108   title,
109   filename,
110   autoWidth
111 }) => {
112   const wb = XLSX.utils.book_new();
113   const arr = json_to_array(key, data);
114   arr.unshift(title)
115   const ws = XLSX.utils.aoa_to_sheet(arr);
116   if (autoWidth) {
117     auto_width(ws, arr);
118   }
119   XLSX.utils.book_append_sheet(wb, ws, filename);
120   XLSX.writeFile(wb, filename + '.xlsx');
121 }
122 
123 // 导出带有汉字标题的execel内容
124 export const export_array_to_excel2 = ({
125   key,
126   data,
127   title,
128   filename,
129   autoWidth
130 }) => {
131   const wb = XLSX.utils.book_new();
132   const arr = json_to_array(key, data);
133   arr.unshift(key)
134   arr.unshift(title)
135   const ws = XLSX.utils.aoa_to_sheet(arr);
136   if (autoWidth) {
137     auto_width(ws, arr);
138   }
139   XLSX.utils.book_append_sheet(wb, ws, filename);
140   XLSX.writeFile(wb, filename + '.xlsx');
141 }
142 
143 export const read = (data, type) => {
144   /* if type == 'base64' must fix data first */
145   // const fixedData = fixdata(data)
146   // const workbook = XLSX.read(btoa(fixedData), { type: 'base64' })
147   const workbook = XLSX.read(data, {
148     type: type
149   });
150   const firstSheetName = workbook.SheetNames[0];
151   const worksheet = workbook.Sheets[firstSheetName];
152   const header = get_header_row(worksheet);
153   const results = XLSX.utils.sheet_to_json(worksheet);
154   return {
155     header,
156     results
157   };
158 }
159 
160 export const readesxle = async (file, header, jsointitle) => {
161   return new Promise(function (resolve, reject) {
162     const resultdata = {
163       ErrCode: "9",
164       ErrText: '导入文件格式不正确。',
165       Rows: []
166     }
167     const fileExt = file.name.split('.').pop().toLocaleLowerCase()
168     if (fileExt === 'xlsx' || fileExt === 'xls') {
169       const reader = new FileReader();
170 
171       const thisXLSX = XLSX;
172       const thisheader = header;
173       const thisjsointitle = jsointitle;
174       reader.readAsArrayBuffer(file)
175       reader.onloadstart = e => {}
176       // reader.onprogress = e => {
177       //   this.progressPercent = Math.round(e.loaded / e.total * 100)
178       // }
179       reader.onerror = e => {
180         resultdata.ErrText = '文件读取出错';
181         resultdata.ErrCode = "1";
182         resolve(resultdata);
183       }
184       reader.onload = e => {
185         const data = e.target.result
186         const
187           workbook = thisXLSX.read(data, {
188             type: "array"
189           });
190         let tempFlag = true;
191 
192         const firstSheetName = workbook.SheetNames[0];
193         const worksheet = workbook.Sheets[firstSheetName];
194         const sheetsheader = get_header_row(worksheet);
195         const sheetarray = thisXLSX.utils.sheet_to_json(worksheet);
196 
197         thisheader.forEach((item, index) => {
198           if (sheetsheader.findIndex(x => x == item) == -1) {
199             tempFlag = false
200           }
201         });
202         if (tempFlag) {
203           let sheetresult = [];
204           for (let i = 0; i < sheetarray.length; i++) {
205             sheetresult.push({});
206             for (let j = 0; j < thisheader.length; j++) {
207               if (sheetarray[i][thisheader[j]] == undefined || sheetarray[i][thisheader[j]] == null)
208                 sheetresult[i][thisjsointitle[j]] = "";
209               else
210                 sheetresult[i][thisjsointitle[j]] = sheetarray[i][thisheader[j]];
211             }
212           }
213           resultdata.ErrCode = "0";
214           resultdata.EErrText = "文件导入成功";
215           resultdata.Rows = sheetresult;
216         } else {
217           resultdata.ErrCode = "1";
218           resultdata.EErrText = "导入文件格式不正确。";
219           resultdata.Rows = [];
220         }
221         resolve(resultdata);
222       }
223     } else {
224       resultdata.ErrCode = "1";
225       resultdata.ErrText = '文件:' + file.name + '不是EXCEL文件,请选择后缀为.xlsx或者.xls的EXCEL文件。';
226       resolve(resultdata);
227     }
228   })
229 }
230 
231 export default {
232   export_table_to_excel,
233   export_array_to_excel,
234   export_json_to_excel,
235   export_array_to_excel2,
236   read,
237   readesxle
238 }
excel.js
3.导出pdf
 
        最开始使用jspdf 包 把 需要导出的table使用 canvas生成图片,然后把图片插入pdf内,但是这种方式不容易控制,并且生成的pdf清晰度不高,如果直接写pdf又会产生对中文支持的不友好,后采用前后端配合生成pdf文件并导出
使用blob的方式 后端返回文件流前端 接收并下载
主要代码如下
 1 //思路 webapi返回二进制的文件流 js 通过Blob接收并转换成pdf文件下载
 2 this.$axios({
 3 method: "post",
 4 Prefix: "",
 5 data: {
 6 ExCode: "IRAP_RPT_DownLoadFile",
 7 fileName: this.exportFileName,
 8 access_token: this.$cookies.get("access_token"),
 9 valueKeys: valueKeys, //"Product,Version,Description",
10 labeNames: labeNames, // "产品,版本,描述",
11 tableData: tableData
12 }
13 // responseType:'blob'
14 })
15 .then(response => {
16 // base64字符串转 byte[]
17 var bstr = atob(response.data.FileInfo),
18 n = bstr.length,
19 u8arr = new Uint8Array(n);
20 while (n--) {
21 u8arr[n] = bstr.charCodeAt(n);
22 }
23 // 转blob
24 var blob = new Blob([u8arr], {
25 type: `application/pdf;charset-UTF-8`
26 });
27 
28 if (this.MyBrowserIsIE()) {
29 // IE10以及Edge浏览器
30 var BOM = "\uFEFF";
31 // 传入 Blob 对象
32 navigator.msSaveBlob(blob, `${this.exportFileName}.pdf`);
33 } else {
34 // 非ie 浏览器
35 let content = window.URL.createObjectURL(blob);
36 this.createDownLoadClick(content, `${this.exportFileName}.pdf`);
37 }
38 })
39 .catch(err => {
40 console.log(err);
41 });
因为公司接口通用规范我这里返回的是文件的base64字符串
如果后台直接返回了二进制的文件流 就不用再次进行转换 并且需要加上responseType:'blob'这句
 
后台接口采用C# webapi 的方式主要代码如下
public string DownLoadFile(string clientID, string msgFormat, string inParam)
        {
            dynamic res = new System.Dynamic.ExpandoObject();
            try
            {
                dynamic dn = inParam.GetSimpleObjectFromJson();
                string token = dn.access_token.ToString();
                // 解析Json 字符串中的数组然后 转实体对象
                string fileName = dn.fileName;
                string lbelObj = dn.labeNames;
                string valueKeyObj = dn.valueKeys;
                object[] tableObj = dn.tableData;
                string tableJson = JsonConvert.SerializeObject(tableObj);
                string[] valueKeys = valueKeyObj.Split(',');
                string[] labeNames = lbelObj.Split(',');
                //string[] valueKeys = new string[] { "Product", "Version",  "Description" }; ;
                //string[] labeNames = new string[] { "产品", "版本", "描述" }; ;
                DataTable tblDatas = new DataTable("Datas");
                //string jsonStr =  "[{\"Product\":\"1\",\"Version\":\"1\",\"Description\":\"1\"}]";
                tblDatas = ToDataTableTwo(tableJson);
                PDFHelper pdfHelper = new PDFHelper();
                byte[] array = pdfHelper.ExportPDF(fileName, labeNames, tblDatas,  valueKeys);
                // 文件byte数组转base64字符串
                string str = Convert.ToBase64String(array);;
                byte[] bt = array.ToArray();
                res.ErrCode = 0;
                res.ErrText = "文件生成成功";
                res.FileInfo = str;
                return JsonConvert.SerializeObject(res);
            }
            catch (Exception ex)
            {
                //throw new Exception(ex.Message);
                res.ErrCode = 9999;
                res.ErrText = "Excel导入异常:" + ex.Message;
                return JsonConvert.SerializeObject(res);
            }
        }

C# pdf生成 使用itextsharp

 

完整js前台代码

  1 
 15 
vue通用导出组件

父组件调用代码

1 2             :isPagination="isPagination" :exportData="exportData" :exportColumns="exportColumns" ref="MyExportType">

 

如果父组件分页的需要导出所有未分页的数据 需要再次调用查询table数据的接口并且给exportData赋值

   async myRepeatExprot(name) {
        // 查询所有
        await this.geBTtResult(1)
        // 调用子组件的导出事件
        await this.$refs.MyExportType.exportFile(name)
      },

否则 未分页或者导出当前页 直接导出即可 不需要通过父组件调用子组件事件

 第一次写博文,有点紧张和言语不清忘见量,如果此文章对您有些许帮助,请给作者一些鼓励,或者留下您的意见

                                                             wexin                                      alipay

                                                  vue实现通用导出(excel,csv, pdf文件)组件 前端导出_第2张图片        vue实现通用导出(excel,csv, pdf文件)组件 前端导出_第3张图片

 

 

转载于:https://www.cnblogs.com/muyangw/p/10306152.html

你可能感兴趣的:(vue实现通用导出(excel,csv, pdf文件)组件 前端导出)