前端文件下載的幾種方式
// 1. 直接下載 (針對一些瀏覽器無法識別的文件格式,直接在地址欄上輸入URL即可觸發瀏覽器的下載功能)
window.location.href = URL;
window.open(URL);
// 2. 直接下載 使用A標簽download屬性
<a href="file.xlsx" download="文件名">文件下載</a>
// 3. 通過觸發JS直接下載
function dowloadFile(fileName, link) {
let DownloadLink= document.createElement('a')
DownloadLink.style = 'display: none;'
DownloadLink.download = fileName
DownloadLink.href = link
document.body.appendChild(DownloadLink)
DownloadLink.click();
document.body.removeChild(DownloadLink)
}
// 通過 ajax 請求, 獲取流數據的方式導出
// 獲取數據時,必須加上(responseType: "blob"), 表示后台穿過來的數據用 'blob' 對象接收
axios.post("ajaxUrl", { responseType: "blob" })
// 下載流文件公共方法
downloadBlobFile(response, fileName = '') {
const fileInfo = response.headers['content-disposition'].split(';')[1]
let _fileName = fileName || decodeURIComponent(fileInfo && fileInfo.split('=')['1'])
let blob = new Blob([response.data])
let href = window.URL.createObjectURL(blob) //創建下載的鏈接
if (window.navigator.msSaveBlob) {
try {
window.navigator.msSaveBlob(blob, _fileName)
} catch (e) {
console.error(e)
}
} else {
// 谷歌瀏覽器 創建a標簽 添加download屬性下載
let downloadElement = document.createElement('a')
downloadElement.href = href
downloadElement.target = '_blank'
downloadElement.download = _fileName //下載后文件名
document.body.appendChild(downloadElement)
downloadElement.click() //點擊下載
document.body.removeChild(downloadElement) //下載完成移除元素
window.URL.revokeObjectURL(href) //釋放掉blob對象
}
}
SheetJS 生成/解析 Excel 介紹
SheetJs Github
使用SheetJS
的xlsx.js
實現生成excel
表格
純JS即可讀取/生成excel
,功能強大,支持多種格式,兼容性高
xlsx.js
提供了一個中間層用於操作數據,將不同類型的文件抽象成同一個js
對象,從而規避了操作不同種類數據之間的復雜性。
基本概念
- 工作簿 workbook 對象:指的是整份 Excel 文檔。
- 工作表 worksheet 對象:指的是 Excel 文檔中的表。可以包含很多張表,每張表對應一個 worksheet 對象
- 單元格 cell 對象:指的就是 worksheet 中的單元格,一個單元格就是一個 cell 對象
{
"SheetNames": ["sheet1"],
"Sheets": {
"Sheet1": {
!ref: “A1:J3”, // 單元格范圍
!rows: [], // 表格行屬性
!cols: [
{wpx: 90}
], // 單元格屬性
!merges: [], // 單元格合並規則
A1/B1/C1...: {}, // 對應excel中的每一個具體的單元格
}
}
}
單元格對象
sheet
中的: A1/B1/C1...: 單元格描述信息
屬性 | 描述 |
---|---|
t | 表示內容類型 |
v | 原始值 |
f | 公式,如: B2 + B3 |
h | HTML內容 |
w | 格式化后的內容 |
r | 富文本內容 |
!merges合並單元格
// 數組的每一項,代表其中一個單元格的合並要求
ws['!merges'] = [
[s: {r: 0, c: 0}, e: {r: 1, c: 0}],
[s: {r: 0, c: 1}, e: {r: 1, c: 1}]
]
// s: 代表合並的起始位置
// e: 代表合並的結束位置
// r: 代表行數
// c: 代表列數
// 數組的第一個對象,表達的含義為: 以0行0列(對應單元格A1)作為起始,以1行0列(對應單元格A2)作為結束,合並這些單元格
單元格地址
xlsx
使用有兩種方式來描述操作中的單元格區域:
- 一種是單元格地址對象 (Cell address object)
// 地址對象描述的是一個起始坐標(從0開始)到結束坐標之間的范圍
const start = { c: 0, r: 0 };
const end = { c: 1, r: 1 };
- 另一種是地址范圍 (Cell range)
// 地址范圍就是Excel中的引用樣式
const range = 'A1:B2'
worksheet Object 工作表對象
{
"sheet1": {
"A1": {}, // 單元格對象
"!ref": "A1:B5", // 表示工作表范圍
“!cols”: [
[ wpx: 200 ], // 設置第1列列狂為200箱數
[ wch: 50 ], // 設置第2列列寬為50字符
],
"!merges": [
{
s: { c: 1, r: 1 }, // B2
s: { c: 3, r: 3 }, // D4
}
], // 合並單元格范圍數據
"!freeze": {
"xSplit": "1", // 凍結列
“ySplit": "1", // 凍結行
}
}
}
xlsx.js
引入
// 以 script 標簽的形式
<script lang="javascript" src="dist/xlsx.full.min.js"></script>
// 使用 npm 安裝 xlsx 模塊
npm install xlsx --save
// 引入
import XLSX from 'xlsx'
// 或
const XLSX = require('xlsx')
xlsx.js
的一些常用方法
讀取數據並解析:
方法名 | 描述 |
---|---|
XLSX.readFile(filename[, opts]) |
獲取數據 |
xlsx.readFileSync(filename[, opts]) |
異步獲取數據 |
XLSX.read(data[, opts]) |
解析數據 |
數據導出:
方法名 | 描述 |
---|---|
XLSX.write(workbook[, opts]) |
用來寫入工作簿 workbook |
XLSX.writeFile(workbook, filename[, opts]) |
把 workbook 寫入到特定的文件 filename 中 |
在XLSX.utils
對象中有一些方法可以對單元格和單元格范圍進行轉化
// 編碼行號
XLSX.utils.encode_row(2); // "3"
// 解碼行號
XLSX.utils.decode_row("2"); // 1
// 編碼列
XLSX.utils.encode_col(2); // "C"
// 解碼列
XLSX.utils.decode_col("A"); // 0
// 編碼單元格
XLSX.utils.encode_cell({ c: 1, r: 1 }); // "B2"
// 解碼單元格
XLSX.utils.decode_cell("B1"); // { c: 1, r: 0 }
// 編碼單元格范圍
XLSX.utils.encode_range({
s: { c:1, r: 0 },
e: { c:2, r: 8 }
}); // "B1:C9"
// 解碼單元格范圍
XLSX.utils.decode_range("B1:C9");
// {s: {r: 1, r: 0}, e: {c: 2, r: 8}}
操作工作簿
// 1. 創建一個工作簿
const workBook = XLSX.utils.book_new();
// 2. 創建工作表對象的幾種方式
// 使用二維數組創建一個工作表對象
const workSheet = XLSX.utils.aoa_to_sheet(data);
// 使用對象數據創建一個工作表對象
const workSheet = XLSX.utils.json_to_sheet(data);
// 根據已渲染好的表格,轉成工作表數據,會自動識別對應的單元格合並數據
const workSheet = XLSX.utils.table_to_sheet("表格ID")
// 向工作簿追加一個工作表
XLSX.utils.book_append_sheet(workBook, workSheet, "工作表名稱")
數據填充 - 創建工作表
工作表是實際存放數據的地方,大部分情況下我們的操作都是在對工作表對象的小左。
aoa_to_sheet
根據二維數組創建工作表
var data1 = [
['主要信息', null, null, '其它信息'],
['姓名', '性別', '年齡', '注冊時間'],
['張三', '男', 18, new Date()],
['李四', '女', 22, new Date()]
];
// 1. 新建一個工作簿
let workbook = XLSX.utils.book_new();
// 2. 生成一個工作表,
// 2.1 aoa_to_sheet 把數組轉換為工作表
let sheet1 = XLSX.utils.aoa_to_sheet(data1);
// 3. 設置單元格合並
sheet1['!merges'] = [
// 設置A1-C1的單元格合並
{ s: {r: 0, c: 0}, e: {r: 0, c: 2 }}
];
// 4.在工作簿中添加工作表
XLSX.utils.book_append_sheet(workbook, sheet1, "工作表名稱");
// 5.輸出工作表,由文件名決定的輸出格式
XLSX.writeFile(workbook, "默認的導出文件名稱.xlsx");
**json_to_sheet
根據二維數組創建工作表: **
const data = [
{ L: 8, O: 5, V: 2, E: 7, ID: 'i_8527' },
{ L: 1, O: 5, V: 9, E: 2, IDL 'i_15926'}
]
// 基礎版: 會自動提起鍵名作為表頭
let worksheet = XLSX.utils.json_to_sheet(data)
展示結果:
L | O | V | E | ID |
---|---|---|---|---|
8 | 5 | 2 | 7 | i_8527 |
1 | 5 | 9 | 2 | I_15926 |
排序並自定義表頭
// 自定義表格的名稱
const headerDisplay = {
L: "L欄", O: "O欄", V: "V欄", E: "E欄", ID: "ID欄"
}
const newData = [headerDisplay, ...data]
let worksheet = XLSX.utils.json_to_sheet(data, {
header: ['ID'] // 表格列排序, 示吧ID移動到最前面
skipHeader: true // 忽略表格原有的表頭
})
ID | L | O | V | E |
---|---|---|---|---|
i_8527 | 8 | 5 | 2 | 7 |
I_15926 | 1 | 5 | 9 | 2 |
數據填充 - 修改工作表數據
// 創建工作表
const worksheet = XLSX.utils.json_to_sheet([
{ '列1': 1, '列2': 2, '列3': 3 },
{ '列1': 4, '列2': 5, '列3': 6 }
], {
header: ['列3', '列2', '列1'], // 排序
skipHeader: true
})
// 修改成新數據 sheet_to_aoa 二維數組方式
XLSX.utils.sheet_to_aoa(worksheet, [
['姓名', '年齡', '地址'],
["張三", 26, "北京"],
["小右", 18, "成都"]
],{
origin: 'A1' // 從A1開始增加內容
})
// -------------------------------
// 修改成新數據 sheet_to_json 方式
XLSX.utils.sheet_to_json(worksheet, [
{ "年齡": 26, "地址": "深圳", "姓名": "張三" },
{ "年齡": 18, "地址": "成都", "姓名": "小右" },
], {
origin: "A1",
header: ["姓名", "年齡", "地址"],
skipHeader: true
})
姓名 | 年齡 | 地址 |
---|---|---|
張三 | 26 | 深圳 |
小右 | 18 | 成都 |
導出Excel文件
根據已經渲染好的表格進行導出Excel :會自動識別單元格合並
/**
* arrTableId 傳參 多條表示有多個表
* [
* {id: 'excel1', sheetName: 'sheet1'},
* {id: 'excel2', sheetName: 'sheet2'}
* ]
*/
export function exportTableToExcel(arrTableId, excelFileName) {
const workbook = XLSX.utils.book_new();
// 循環得到每一張表的 sheet,並添加到 workbook 中
arrTableId.forEach((item) => {
const tableEle = document.getElementById(item.id);
const ws = XLSX.utils.table_to_sheet(tableEle);
XLSX.utils.book_append_sheet(workbook, ws, item.sheetName)
})
// 導出Excel
XLSX.writeFile(workbook, excelFileName)
}
// 使用
const exportParams = [{ id: "xGrid1", sheetName: "工作表名稱" }]
this.exportTableToExcel(exportParams, "導出后保存的文件名稱.xlsx");
根據 aoa_to_sheet
和json_to_sheet
創建的工作表進行導出,復雜表頭需要提供合並的 !merges
數據
// 復雜表頭示例
const workbook = XLSX.utils.book_new();
const data = [
// 特別注意: 合並的地方后面預覽 null
[ "主要信息", null, null, "其他信息" ],
[ "姓名", "性別", "年齡", "注冊時間" ],
[ "張三", "男", 26, new Date() ],
[ "李四", "女", 18, new Date() ]
]
const sheet = XLSX.utils.aoa_to_sheet(data);
sheet['!merges'] = [
// 設置A1-C1的單元格合並
{ s: { r: 0, c: 0 }, e: { r: 0, c: 2 }}
]
XLSX.utils.book_append_sheet(workbook, ws, sheet)
// 導出Excel
XLSX.writeFile(workbook, excelFileName)
合並單元格方案
需要自己提供單元格合並范圍的數據
const mergesArr = ['A1:A3', 'B1:F1', 'B2:B3', 'C2:F2']
const range = ["A1:A3", "B1:F1", "B2:B3", "C2:F2"].map((item) => {
return XLSX.utils.decode_range(item);
});
sheet1["!merges"] = range;