JS文件导入导出
灵扁扁 人气:0一、需求场景描述
文件的导入导出是非常常见的需求功能,excel文件的导入导出更为常见,实践中许多时候,是调用接口实现导入导出的,也就是说将文件导入导出的逻辑交给后端去做了。但是,有的时候确也需要前端自行实现导入导出,此时前端实现导入导出可能是更好的选择。
1.此时前端上传解析excel文件可能更合适
例如,一个常规excel文件填写模板,在用户的电脑上,用户上传完后,还可以在预览展示时,在线修改,改完可以下载,也可以将数据给到服务端,但这时,比如这模板数据通常不多,比如是一个团队成员这样的数据,通过文件流的形式传给后端,可能不是很理想,倒不如前端解析传那几行数据就行。
这种场景下,需要前端做到上传并解析excel文件。
2.此时前端下载excel文件可能优雅一些
支持用户动态增减筛选数据的界面,由于这种频繁的变更不是实时变更到服务器的,因此服务器其实没有存有刚刚用户的增减筛选的操作结果,此时由于前端主导下载可能更合适。当然,把操作的最终结果更新到服务器再告知服务器提供下载也是可行的。
这种场景下,需要前端做到过滤解析数据,然后做excel文件的下载。
实践效果图如下:
二、实现思路分析
1.导入excel文件实现思路分析
- 1.使用html支持上传标签从本地获取文件,例如type为file的input,el-upload等。
- 2.利用FileReader将文件读取为二进制字符串。
- 3.使用XLSX插件的XLSX.read()方法,将二进制字符串转换成excel文件的工作蒲对象workbook(简写成wb)。
- 4.通过XLSX.utils.sheet_to_json()方法,从wb中获取第一张 Sheets表格数据并将其转换为json数据。
- 5.重组json数据生成数组,即是根据自己的定义的列字段名,重新组成符合自己需求的json数据。因为从excel中提取的数据是没有字段名或字段名不符合要求的,
而我们需要渲染在页面表格中又确实需要合适的字段名。
2.导出excel文件实现思路分析
- 1.通过XLSX插件的 XLSX.utils.book_new()方法,创建excel工作蒲对象wb。
- 2.按需插入第一行数据,通过数组的unshift()方法。
- 3.通过XLSX.utils.json_to_sheet(),创建excel表格对象ws。
- 4.通过json_to_array(key,data),结合自定义的字段名key,和数据记录data,生成新数组。
- 5.通过auto_width(),对ws和新生成的数组,自动计算各列col宽。
- 6.通过XLSX.utils.book_append_sheet(),生成实际excel工作蒲,并使用XLSX.writeFile()生成excel文件。
三、关键代码
1. exportExcel.js 导出excel文件
/* eslint-disable */ /* 导出excel文件 */ /** * 导出excel文件实现思路分析 * * 1.通过XLSX插件的 XLSX.utils.book_new()方法,创建excel工作蒲对象wb。 * 2.按需插入第一行数据,通过数组的unshift()方法。 * 3.通过XLSX.utils.json_to_sheet(),创建excel表格对象ws。 * 4.通过json_to_array(key,data),结合自定义的字段名key,和数据记录data,生成新数组。 * 5.通过auto_width(),对ws和新生成的数组,自动计算各列col宽。 * 6.通过XLSX.utils.book_append_sheet(),生成实际excel工作蒲,并使用XLSX.writeFile()生成excel文件。 */ import XLSX from 'xlsx' // 自动计算col列宽 function auto_width (ws, data) { /*set worksheet max width per col*/ const colWidth = data.map(row => row.map(val => { /*if null/undefined*/ if (val == null) { return { 'wch': 10 } } /*if chinese*/ else if (val.toString().charCodeAt(0) > 255) { return { 'wch': val.toString().length * 2 } } else { return { 'wch': val.toString().length } } })) /*start in the first row*/ let result = colWidth[0] for (let i = 1; i < colWidth.length; i++) { for (let j = 0; j < colWidth[i].length; j++) { if (result[j]['wch'] < colWidth[i][j]['wch']) { result[j]['wch'] = colWidth[i][j]['wch'] } } } ws['!cols'] = result } // 将json数据转换成数组 function json_to_array (key, jsonData) { return jsonData.map(v => key.map(j => { return v[j] })) } /** * @param header Object,表头 * @param data Array,表体数据 * @param key Array,字段名 * @param title String,标题(会居中显示),即excel表格第一行 * @param filename String,文件名 * @param autoWidth Boolean,是否自动根据key自定义列宽度 */ export const exportJsonToExcel = ({ header, data, key, title, filename, autoWidth }) => { const wb = XLSX.utils.book_new() if (header) { data.unshift(header) } if (title) { data.unshift(title) } const ws = XLSX.utils.json_to_sheet(data, { header: key, skipHeader: true }) if (autoWidth) { const arr = json_to_array(key, data) auto_width(ws, arr) } XLSX.utils.book_append_sheet(wb, ws, filename) XLSX.writeFile(wb, filename + '.xlsx') } export default { exportJsonToExcel }
2. importExcel.js 导入excel文件
/* eslint-disable */ /* 导入excel文件 */ /** * 导入excel文件实现思路分析 * * 1.使用html支持上传标签从本地获取文件,例如type为file的input,el-upload等。 * 2.利用FileReader将文件读取为二进制字符串。 * 3.使用XLSX插件的XLSX.read()方法,将二进制字符串转换成excel文件的工作蒲对象workbook(简写成wb)。 * 4.通过XLSX.utils.sheet_to_json()方法,从wb中获取第一张 Sheets表格数据并将其转换为json数据。 * 5.重组json数据生成数组,即是根据自己的定义的列字段名,重新组成符合自己需求的json数据。因为从excel中提取的数据是没有字段名或字段名不符合要求的, * 而我们需要渲染在页面表格中又确实需要合适的字段名。 */ /** * @param file 文件流 * @param tableTemplate 要导入的表格模板,一个数组,如: * tableTemplate: ['userCode', 'userName', 'department', 'major', 'position'],其中的值 * 为表格的字段名,注意字段的顺序应与实际的导入excel一致。 */ export default function importExcel (file, tableTemplate) { return new Promise((resolve, reject) => { let f = file.raw // 获取文件内容 // 通过DOM取文件数据 let rABS = false // 是否将文件读取为二进制字符串 let reader = new FileReader() FileReader.prototype.readAsBinaryString = function (f) { let binary = '' let rABS = false // 是否将文件读取为二进制字符串 let wb // 读取完成的数据 let outdata let reader = new FileReader() reader.onload = function (e) { let bytes = new Uint8Array(reader.result) let length = bytes.byteLength for (let i = 0; i < length; i++) { binary += String.fromCharCode(bytes[i]) } let XLSX = require('xlsx') if (rABS) { wb = XLSX.read(btoa(binary), { // 手动转化 type: 'base64' }) } else { wb = XLSX.read(binary, { type: 'binary' }) } outdata = XLSX.utils.sheet_to_json(wb.Sheets[wb.SheetNames[0]]) // outdata就是表格中的值 let arr = [] // 下面是数据解析提取逻辑 if (tableTemplate.length > 0) { let tempArr = Object.keys(outdata[0]) let tempArrNew = [] for (let i in tempArr) { for (let k in tableTemplate) { if (i === k) { tempArrNew.push({fieldE: tableTemplate[k], fieldC: tempArr[i]}) } } } tempArr = tempArrNew outdata.map(item => { let obj = {} tempArr.map(temp2 => { obj[temp2.fieldE] = item[temp2.fieldC] }) arr.push(obj) }) } resolve(arr) } reader.readAsArrayBuffer(f) } if (rABS) { reader.readAsArrayBuffer(f) } else { reader.readAsBinaryString(f) } }) }
四、使用示例
1.使用示例一:上传解析excel
关键 html 代码部分
<el-upload action="" id="upload-excel" :on-change="handleChange" :show-file-list="false" accept="application/vnd.openxmlformats-officedocument.spreadsheetml.sheet,application/vnd.ms-excel" :auto-upload="false"> </el-upload> <el-table class="cn-table-th-bg" size="small" :data="tableData" border style="width: 100%"> <el-table-column type="index" label="序号" width="50" align="center"></el-table-column> <el-table-column prop="userSource" label="来源" align="center"></el-table-column> <el-table-column prop="userCode" label="工号" align="center"></el-table-column> <el-table-column prop="userName" label="姓名" align="center"></el-table-column> <el-table-column prop="department" label="部门" align="center"></el-table-column> <el-table-column prop="major" label="专业" align="center"></el-table-column> <el-table-column prop="position" label="职务/职称" align="center"></el-table-column> <el-table-column label="操作" align="center" width="250"> <template slot-scope="scope"> <el-button @click="clickDelete(scope.row)" size="mini">删除</el-button> <el-button @click="moveUp(tableData,scope.$index)" size="mini" class="up-button">上移</el-button> <el-button @click="moveDown(tableData,scope.$index)" size="mini" class="down-button">下移</el-button> </template> </el-table-column> </el-table>
// 关键 js 代码部分
import importExcel from '@/utils/excel/importExcel' handleChange (file, fileList) { tableField: ['userCode', 'userName', 'department', 'major', 'position'], importExcel(file, tableField).then(res => { this.tableData = res }) }
2.使用示例二:下载excel文件
关键 js 代码
import { exportJsonToExcel } from '@/utils/excel/exportExcel' clickDownload () { const tableField = ['userCode', 'userName', 'department', 'major', 'position'], tableHeader = {userCode: '工号', userName: '姓名', department: '部门', major: '专业', position: '职位/职称'}, tableTitle = '导出表格', templateData = [ {'userCode': 'N1001', 'userName': '张三', 'department': '综合管理部', 'major': '计算机科学与技术', 'position': '项目经理'} ], obj = { header: tableHeader, data: templateData, key: tableField, title: '', filename: '团队成员导入模板', autoWidth: true } exportJsonToExcel(obj) },
加载全部内容