JavaScript實現(xiàn)excel文件導(dǎo)入導(dǎo)出
一、需求場景描述
文件的導(dǎo)入導(dǎo)出是非常常見的需求功能,excel文件的導(dǎo)入導(dǎo)出更為常見,實踐中許多時候,是調(diào)用接口實現(xiàn)導(dǎo)入導(dǎo)出的,也就是說將文件導(dǎo)入導(dǎo)出的邏輯交給后端去做了。但是,有的時候確也需要前端自行實現(xiàn)導(dǎo)入導(dǎo)出,此時前端實現(xiàn)導(dǎo)入導(dǎo)出可能是更好的選擇。
1.此時前端上傳解析excel文件可能更合適
例如,一個常規(guī)excel文件填寫模板,在用戶的電腦上,用戶上傳完后,還可以在預(yù)覽展示時,在線修改,改完可以下載,也可以將數(shù)據(jù)給到服務(wù)端,但這時,比如這模板數(shù)據(jù)通常不多,比如是一個團(tuán)隊成員這樣的數(shù)據(jù),通過文件流的形式傳給后端,可能不是很理想,倒不如前端解析傳那幾行數(shù)據(jù)就行。
這種場景下,需要前端做到上傳并解析excel文件。
2.此時前端下載excel文件可能優(yōu)雅一些
支持用戶動態(tài)增減篩選數(shù)據(jù)的界面,由于這種頻繁的變更不是實時變更到服務(wù)器的,因此服務(wù)器其實沒有存有剛剛用戶的增減篩選的操作結(jié)果,此時由于前端主導(dǎo)下載可能更合適。當(dāng)然,把操作的最終結(jié)果更新到服務(wù)器再告知服務(wù)器提供下載也是可行的。
這種場景下,需要前端做到過濾解析數(shù)據(jù),然后做excel文件的下載。
實踐效果圖如下:
二、實現(xiàn)思路分析
1.導(dǎo)入excel文件實現(xiàn)思路分析
- 1.使用html支持上傳標(biāo)簽從本地獲取文件,例如type為file的input,el-upload等。
- 2.利用FileReader將文件讀取為二進(jìn)制字符串。
- 3.使用XLSX插件的XLSX.read()方法,將二進(jìn)制字符串轉(zhuǎn)換成excel文件的工作蒲對象workbook(簡寫成wb)。
- 4.通過XLSX.utils.sheet_to_json()方法,從wb中獲取第一張 Sheets表格數(shù)據(jù)并將其轉(zhuǎn)換為json數(shù)據(jù)。
- 5.重組json數(shù)據(jù)生成數(shù)組,即是根據(jù)自己的定義的列字段名,重新組成符合自己需求的json數(shù)據(jù)。因為從excel中提取的數(shù)據(jù)是沒有字段名或字段名不符合要求的,
而我們需要渲染在頁面表格中又確實需要合適的字段名。
2.導(dǎo)出excel文件實現(xiàn)思路分析
- 1.通過XLSX插件的 XLSX.utils.book_new()方法,創(chuàng)建excel工作蒲對象wb。
- 2.按需插入第一行數(shù)據(jù),通過數(shù)組的unshift()方法。
- 3.通過XLSX.utils.json_to_sheet(),創(chuàng)建excel表格對象ws。
- 4.通過json_to_array(key,data),結(jié)合自定義的字段名key,和數(shù)據(jù)記錄data,生成新數(shù)組。
- 5.通過auto_width(),對ws和新生成的數(shù)組,自動計算各列col寬。
- 6.通過XLSX.utils.book_append_sheet(),生成實際excel工作蒲,并使用XLSX.writeFile()生成excel文件。
三、關(guān)鍵代碼
1. exportExcel.js 導(dǎo)出excel文件
/* eslint-disable */ /* 導(dǎo)出excel文件 */ /** * 導(dǎo)出excel文件實現(xiàn)思路分析 * * 1.通過XLSX插件的 XLSX.utils.book_new()方法,創(chuàng)建excel工作蒲對象wb。 * 2.按需插入第一行數(shù)據(jù),通過數(shù)組的unshift()方法。 * 3.通過XLSX.utils.json_to_sheet(),創(chuàng)建excel表格對象ws。 * 4.通過json_to_array(key,data),結(jié)合自定義的字段名key,和數(shù)據(jù)記錄data,生成新數(shù)組。 * 5.通過auto_width(),對ws和新生成的數(shù)組,自動計算各列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數(shù)據(jù)轉(zhuǎn)換成數(shù)組 function json_to_array (key, jsonData) { return jsonData.map(v => key.map(j => { return v[j] })) } /** * @param header Object,表頭 * @param data Array,表體數(shù)據(jù) * @param key Array,字段名 * @param title String,標(biāo)題(會居中顯示),即excel表格第一行 * @param filename String,文件名 * @param autoWidth Boolean,是否自動根據(jù)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 導(dǎo)入excel文件
/* eslint-disable */ /* 導(dǎo)入excel文件 */ /** * 導(dǎo)入excel文件實現(xiàn)思路分析 * * 1.使用html支持上傳標(biāo)簽從本地獲取文件,例如type為file的input,el-upload等。 * 2.利用FileReader將文件讀取為二進(jìn)制字符串。 * 3.使用XLSX插件的XLSX.read()方法,將二進(jìn)制字符串轉(zhuǎn)換成excel文件的工作蒲對象workbook(簡寫成wb)。 * 4.通過XLSX.utils.sheet_to_json()方法,從wb中獲取第一張 Sheets表格數(shù)據(jù)并將其轉(zhuǎn)換為json數(shù)據(jù)。 * 5.重組json數(shù)據(jù)生成數(shù)組,即是根據(jù)自己的定義的列字段名,重新組成符合自己需求的json數(shù)據(jù)。因為從excel中提取的數(shù)據(jù)是沒有字段名或字段名不符合要求的, * 而我們需要渲染在頁面表格中又確實需要合適的字段名。 */ /** * @param file 文件流 * @param tableTemplate 要導(dǎo)入的表格模板,一個數(shù)組,如: * tableTemplate: ['userCode', 'userName', 'department', 'major', 'position'],其中的值 * 為表格的字段名,注意字段的順序應(yīng)與實際的導(dǎo)入excel一致。 */ export default function importExcel (file, tableTemplate) { return new Promise((resolve, reject) => { let f = file.raw // 獲取文件內(nèi)容 // 通過DOM取文件數(shù)據(jù) let rABS = false // 是否將文件讀取為二進(jìn)制字符串 let reader = new FileReader() FileReader.prototype.readAsBinaryString = function (f) { let binary = '' let rABS = false // 是否將文件讀取為二進(jìn)制字符串 let wb // 讀取完成的數(shù)據(jù) 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), { // 手動轉(zhuǎn)化 type: 'base64' }) } else { wb = XLSX.read(binary, { type: 'binary' }) } outdata = XLSX.utils.sheet_to_json(wb.Sheets[wb.SheetNames[0]]) // outdata就是表格中的值 let arr = [] // 下面是數(shù)據(jù)解析提取邏輯 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
關(guān)鍵 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="專業(yè)" align="center"></el-table-column> <el-table-column prop="position" label="職務(wù)/職稱" 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>
// 關(guān)鍵 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文件
關(guān)鍵 js 代碼
import { exportJsonToExcel } from '@/utils/excel/exportExcel' clickDownload () { const tableField = ['userCode', 'userName', 'department', 'major', 'position'], tableHeader = {userCode: '工號', userName: '姓名', department: '部門', major: '專業(yè)', position: '職位/職稱'}, tableTitle = '導(dǎo)出表格', templateData = [ {'userCode': 'N1001', 'userName': '張三', 'department': '綜合管理部', 'major': '計算機(jī)科學(xué)與技術(shù)', 'position': '項目經(jīng)理'} ], obj = { header: tableHeader, data: templateData, key: tableField, title: '', filename: '團(tuán)隊成員導(dǎo)入模板', autoWidth: true } exportJsonToExcel(obj) },
到此這篇關(guān)于JavaScript實現(xiàn)excel文件導(dǎo)入導(dǎo)出的文章就介紹到這了,更多相關(guān)JS文件導(dǎo)入導(dǎo)出內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
一文學(xué)會用JS判斷文字是否被省略(ellipsis)
這篇文章主要給大家介紹了用JS如何判斷文字被省略ellipsis,CSS幫我們搞定了省略,但是JS并不知道文本什么時候被省略了,所以我們得通過JS來計算,接下來,我將介紹2種方法來實現(xiàn)JS計算省略,需要的朋友可以參考下2023-08-08javascript特效實現(xiàn)——當(dāng)前時間和倒計時效果的簡單實例
下面小編就為大家?guī)硪黄猨avascript特效實現(xiàn)——當(dāng)前時間和倒計時效果的簡單實例。小編覺得挺不錯的,現(xiàn)在就分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2016-07-07基于jstree使用AJAX請求獲取數(shù)據(jù)形成樹
這篇文章主要為大家詳細(xì)介紹了基于jstree使用AJAX請求獲取數(shù)據(jù)形成樹,具有一定的參考價值,感興趣的小伙伴們可以參考一下2017-08-08