日常開發中,數據導出到文件通常有兩種方式:
- 在
后端處理
,以文件流
或者資源路徑
的方式返回; - 后端返回數據,前端按需
處理后
再觸發瀏覽器的下載事件,已保存到本地文件。
這里介紹后者的一種零依賴的實現方式。
保存內容到文件
通過 JS 創建一個隱藏的超鏈接,并主動點擊觸發下載事件。
/*** 保存內容到文件* @param {*} blob* @param {*} fileName*/
function saveToFile(blob, fileName = "下載文件.txt") {if (!(!!blob && blob.toString() == '[object Blob]')) {blob = new Blob([blob])}let link = document.createElement('a')link.href = window.URL.createObjectURL(blob) // 創建下載的鏈接link.download = fileName // 下載后文件名link.style.display = 'none'document.body.appendChild(link)link.click() // 點擊下載window.URL.revokeObjectURL(link.href) // 釋放掉blob對象document.body.removeChild(link) // 下載完成移除元素
}
生成CSV格式
CSV
(Comma-Separated Values,逗號分隔值)是一種純文本格式,用于以表格形式存儲數據,廣泛應用于數據交換和處理,特別是在電子表格軟件(如 Excel)和數據庫系統之間的數據傳輸中。
處理起來也是比較簡單,將二維數組中的子數組以分隔符(默認英文逗號)連接后以換行符拼接即可。這里需要注意特殊字段的處理:
長字符串
:特別是本身包含換行符(此時使用 ` 包裹)數組
:通過換行符拼接
const NEW_LINE = "\n"/*** 處理特殊字符,若參數為數組則進行換行轉換* @Param {*} v*/
const fixToCsv = v=>{if(Array.isArray(v))return `"${v.join(NEW_LINE).replace(/"/g, "`")}"`if(typeof(v)==='string')return `"${v.replace(/"/g, "`")}"`return v
}/*** 保存到 CSV 默認編碼為 UTF-8* @param {Array|Object} obj - 數據對象,可以是二維數組/Object(包含 headers、rows 屬性)* @param {String} fileName - 文件名* @param {String} newLine - 換行符,默認 \n*/
function saveToCSV(obj, fileName = "下載文件", newLine=NEW_LINE) {let csvText = ""//參數為數組的情況if(Array.isArray(obj)){csvText = Array.isArray(obj[0])? obj.map(v=>v.map(fixToCsv).join(",")).join(newLine): obj.join(newLine)}else if(typeof(obj) === 'object'){let { headers, rows } = objif(!headers && !Array.isArray(headers)) throw Error(`[CSV導出] Object 類型的參數必須傳遞 headers 屬性`)//寫入標題欄csvText += headers.map(h=> typeof(h)==='object'?h.text:h).join(",") + newLinelet headerIds = headers.map(h=> typeof(h)==='object'? h.key:h)rows.forEach((row,rIndex)=>{csvText += headerIds.map(id=>fixToCsv(row[id])).join(",") + newLine})}else if(typeof(obj) === 'string')csvText = objsaveToFile(new Blob([csvText], { type: "application/csv;charset=utf-8" }), `${fileName}.csv`)
}
如何使用
// 拿到后臺數據
const rows = fetch("{API}")
let csv = []
csv.push(["序號","名稱","聯系方式"])
// 處理數據
rows.forEach((row, i)=>{csv.push([`${i+1}`,row.name, row.phone])
})saveToCSV(csv, "用戶導出")
之后瀏覽器會下載最終的 CSV 文件(此時需要注意彈窗攔截)。