======================
FileSaver.js(保存文件)
保存文件:https://github.com/eligrey/FileSaver.js
安装
安装到项目
npm install file-saver --save
或者cdn引入
<script src="./public/cdn/file/FileSaver.js"></script>
引入
如果是npm安装,使用时可以通过import引入
import { saveAs } from "file-saver";
如果是cdn引入,会给你的全局对象(浏览器就是window)添加一个saveAs函数,直接用
window.saveAs
使用
主要是通过函数saveAs( Blob/File/Url, 文件名 , [选项]) 进行操作
选项只有:{ autoBom: true },转换成Unicode,只有blob type 为 charset=utf-8 有效。
如通过二进制格式blob,保存成文件
var blob = new Blob(["Hello, world!"], {type: "text/plain;charset=utf-8"});saveAs(blob, "hello world.txt");//其他格式也可以,比如表格xlsx
保存成图片
var canvas = document.getElementById("my-canvas")canvas.toBlob(function(blob) {saveAs(blob, "pretty image.png");});// 或FileSaver.saveAs("https://httpbin.org/image", "image.jpg");
=======================
ExcelJS(强大,但慢)
https://github.com/exceljs/exceljs
安装
无需安装,外部引入即可
在index.htm内引入
<script src="./public/cdn/file/FileSaver.js"></script><script src="./public/cdn/file/exceljs.min.js"></script>
导出xlsx
//1、表格数据为jsonlet jsonData = [{id:1,name:'yjl',sex:'男'},{id:2,name:'xj',sex:'女'},];//2、创建工作簿let workbook = new ExcelJS.Workbook();//3、工作簿加入工作表let worksheet = workbook.addWorksheet('sheet1');//4、定义列worksheet.columns = [{ header: 'Id', key: 'id', width: 10 },{ header: 'Name', key: 'name', width: 32 },{ header: 'Sex', key: 'sex', width: 10 }];//5、根据数据,给行赋值for (let r in jsonData) {worksheet.addRow(jsonData[r]);}//6、导出workbook.xlsx.writeBuffer().then((data) => {const buff = new Blob([data],{type: "text/plain;charset=utf-8"});saveAs(buff, "hello world.xlsx");}).catch((err)=>{console.log("err: ",err);})
导入
Vue3.0 版本 + TS 版本(不需要TS的话可以自己去掉 lang=’ts’)
<template><div><!-- 弹出选择文件按钮 --><inputid="importBtn"ref="importBtn"type="file"accept=".xlsx,.xls"style="display: none"@change="importSelect"/><!-- 显示的假按钮 --><a-button type="primary" @click="importBtnClick" v-bind="props.btnProps">{{ props.btnText }}</a-button></div></template><script lang='ts'>export default {inheritAttrs: false,name: "importBtn"}</script><script setup lang='ts'>import { ref } from "vue"import ExcelJS from "exceljs"import utils from '@/utils'/** 父组件传入参数 */const props = defineProps({/** 按钮 文本 */btnText: {type: String,default: "导入Excel"},/** 文件大小判断, 单位MB ,0为不限制 */fileSizeLimit:{type:Number,default:0},/** 按钮 属性 */btnProps: {default: {}}})const emits = defineEmits(["selectFile"])/** 显示的假按钮 点击时,触发选择文件 */const importBtnClick = () => {// 重要,重置已选取的路径,因为触发导入事件是通过change改变触发,如果不重置路径,那么重复选同一个文件时会不执行后续代码let impBtn = document.getElementById("importBtn") as HTMLInputElement | nullif (impBtn) {impBtn.value = ""impBtn.click()}}// 导入按钮事件function importSelect() {// 1、通过input打开选择文件窗口,获取文件信息let readFile = document.getElementById("importBtn") as HTMLInputElement// 2、判断用户是否选择了文件if (readFile?.files && readFile.files[0]) {// console.log("用户选择了文件", readFile.files[0])let tempReadFile = readFile.files[0]// 判断选择的文件类型if (tempReadFile.type != "application/vnd.ms-excel" && tempReadFile.type as any != "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet") {utils.notice.showErrorMessage("选择的文件类型不正确")return}// 判断文件大小限制if ( props.fileSizeLimit !=0 && tempReadFile.size>props.fileSizeLimit) {utils.notice.showErrorMessage(`选择的文件大小超过了 ${props.fileSizeLimit}MB `)return}// 3、创建工作簿let workbookRead = new ExcelJS.Workbook()// 4、使用JS的web API FileReader 读取文件信息let reader = new FileReader()// 5、设定FileReader读取时的操作,调用读操作(如readAsArrayBuffer)时就会执行这段reader.onload = function (event) {//读取时是传入读取的事件,事件里面.target.result就是用户选择文件的内容let fileData = event?.target?.result as ArrayBufferif (fileData) {//7、用工作簿读取文件内容,通过ArrayBuffer的方式读取workbookRead.xlsx.load(fileData).then((res) => {// console.log("res: ", res)// 把数据提交父组件emits("selectFile",res)})}}// 6、调用FileReader读取文件,用readAsArrayBuffer的方法,把内容变成ArrayBufferreader.readAsArrayBuffer(readFile.files[0])} else {utils.notice.showErrorMessage("选择文件异常",2)console.log("readFile.files",readFile?.files)}}</script><style lang='less'></style>

工作簿 WorkBook
基本文件信息
//文件信息workbook.creator = 'Me'; //创建人workbook.lastModifiedBy = 'Her'; //最后修改人workbook.created = new Date(1985, 8, 30); //创建时间workbook.modified = new Date(); //修改时间workbook.lastPrinted = new Date(2016, 9, 27); //最后打印时间workbook.properties.date1904 = true;// 将工作簿日期设置为 1904 年日期系统,默认是用1900年
添加、删除工作表
const sheet = workbook.addWorksheet('My Sheet'); //把工作表sheet添加到工作簿workbook,并且命名为My Sheetworkbook.removeWorksheet(sheet.id); //删除工作表
工作表 WorkSheet
列 column
行 row
单元格 cell
表格 table
其他设置、样式
=======================
SheetJS(简单,快速)
https://github.com/SheetJS/sheetjs (要用到保存文件)
文档:https://docs.sheetjs.com/docs
引入模块
推荐通过npm安装
npm install --save https://cdn.sheetjs.com/xlsx-0.18.9/xlsx-0.18.9.tgz
导出表格
//1、假设表格数据为jsonlet jsonData = [{id:1,name:'叶杰麟',sex:'man'},{id:2,name:'xj',sex:'women'},];//2、创建工作表Sheetlet sheet = XLSX.utils.json_to_sheet(jsonData);//3、创建工作簿workBooklet wb = XLSX.utils.book_new();//4、把工作表Sheet,放入工作簿workBook内XLSX.utils.book_append_sheet(wb, sheet, 'sheet1')//5、将工作簿workBook 和 导出选项一起写入let wbout = XLSX.write(wb, {type: 'binary'})//6、创建一个String 转换成 ArrayBuffer的函数function StringToArrayBuffer(string) {let buf = new ArrayBuffer(string.length);let view = new Uint8Array(buf);for (let i = 0; i != string.length; ++i) {view[i] = string.charCodeAt(i) & 0xff;}return buf;}//7、把 workBook和导出选项 转换成 Bloblet blob = new Blob([StringToArrayBuffer(wbout)], {type: "text/plain;charset=utf-8"});//8、导出saveAs(blob, "hello world.xlsx");//其他格式也可以,比如表格xlsx

导入表格
导入表格按钮示例,点击后弹出选择文件对话框,选择文件后通过emits(selectFile) 把结果返回给父组件使用
<template><div><!-- 弹出选择文件按钮 --><inputid="importBtn"ref="importBtn"type="file"accept=".xls,.xlsx"style="display: none"@change="importSelect"/><!-- 显示的假按钮 --><a-button type="primary" @click="importBtnClick" v-bind="props.btnProps">{{ props.btnText }}</a-button></div></template><script lang='ts'>export default {inheritAttrs: false,name: "importBtn"}</script><script setup lang='ts'>import { ref } from "vue"import * as XLSX from 'xlsx'import utils from "@/utils"/** 父组件传入参数 */const props = defineProps({/** 按钮 文本 */btnText: {type: String,default: "导入Excel"},/** 文件大小判断, 单位MB ,0为不限制 */fileSizeLimit: {type: Number,default: 0},/** 按钮 属性 */btnProps: {default: {}}})const emits = defineEmits(["selectFile","handleLoading"])/** 显示的假按钮 点击时,触发选择文件 */const importBtnClick = () => {// 重要,重置已选取的路径,因为触发导入事件是通过change改变触发,如果不重置路径,那么重复选同一个文件时会不执行后续代码let impBtn = document.getElementById("importBtn") as HTMLInputElement | nullif (impBtn) {impBtn.value = ""impBtn.click()}}// 导入按钮事件function importSelect() {emits("handleLoading",true)// 1、通过input打开选择文件窗口,获取文件信息let readFile = document.getElementById("importBtn") as HTMLInputElement// 2、判断用户是否选择了文件if (readFile?.files && readFile.files[0]) {// console.log("用户选择了文件", readFile.files[0])let tempReadFile = readFile.files[0]// 判断选择的文件类型if (tempReadFile.type != "application/vnd.ms-excel" &&(tempReadFile.type as any) !="application/vnd.openxmlformats-officedocument.spreadsheetml.sheet") {utils.notice.showErrorMessage("选择的文件类型不正确")emits("handleLoading",false)return}// 判断文件大小限制if (props.fileSizeLimit != 0 && tempReadFile.size > props.fileSizeLimit) {utils.notice.showErrorMessage(`选择的文件大小超过了 ${props.fileSizeLimit}MB `)emits("handleLoading",false)return}// 3、使用JS的web API FileReader 读取文件信息let reader = new FileReader()// 4、设定FileReader读取时的操作,调用读操作(如readAsArrayBuffer)时就会执行这段reader.onload = function (event) {//读取时是传入读取的事件,事件里面.target.result就是用户选择文件的内容let fileData = event?.target?.result as ArrayBufferif (fileData) {// 7、用sheetJS 的方式读取内容let res = XLSX.read(fileData)console.log('导入按钮的res',res)emits("selectFile", res)emits("handleLoading",false)}}// 5、调用FileReader读取文件,用readAsArrayBuffer的方法,把内容变成ArrayBufferreader.readAsArrayBuffer(readFile.files[0])} else {utils.notice.showErrorMessage("选择文件异常", 2)// console.log("readFile.files", readFile?.files)emits("handleLoading",false)}}</script><style lang='less'></style>
表格选项
单元格 Cell
单元格对象通过sheet[‘A1’]表示,如下图:
其他设置中:
单元地址对象存储为{c:c,r:r},其中c和r分别是0索引列和行号。
例如,单元地址B5由对象{c:1,r:4}表示。
单元格区域对象存储为{s:s,e:e},其中s是第一个单元格,e是范围中的最后一个单元格。范围包括在内。
例如,范围A3:B7由对象{s:{c:0,r:2},e:{c:1,r:6}}表示。
值的类型
| 属性 | 描述 |
|---|---|
v |
单元格显示的值 |
w |
格式化文本 |
t |
b 布尔, e 错误, n 数值, d 日期, s 文本, z 空白单元格(默认不会生成)。所有解析器的默认行为是生成数字形式的日期,将cellDates设置为true将强制生成器存储日期。 |
f |
cell formula encoded as an A1-style string (if applicable) |
F |
range of enclosing array if formula is array formula (if applicable) |
r |
rich text encoding (if applicable) |
h |
HTML rendering of the rich text (if applicable) |
c |
comments associated with the cell |
z |
number format string associated with the cell (if requested) |
l |
cell hyperlink object (.Targetholds link, .Tooltipis tooltip) |
s |
单元格样式 |
| e错误值 | 错误说明 |
|---|---|
0x00 |
#NULL! |
0x07 |
#DIV/0! |
0x0F |
#VALUE! |
0x17 |
#REF! |
0x1D |
#NAME? |
0x24 |
#NUM! |
0x2A |
#N/A |
0x2B |
#GETTING_DATA |
工作表 sheet
打印边距 margins
//2、创建工作表Sheetlet sheet = XLSX.utils.json_to_sheet(jsonData);//设置打印边距,左边距、右边距、上边距、下边距、页眉、页脚sheet["!margins"]={left:0, right:0, top:0,bottom:0,header:0,footer:0};

单元格合并 merges
存放一些单元格合并信息,是一个数组。
每个数组由包含s和e构成的对象组成,s表示开始start,e表示结束end,r表示行row,c表示列colmn,从0开始的;
//2、创建工作表Sheetlet sheet = XLSX.utils.json_to_sheet(jsonData);sheet['!merges']=[{s:{r:4,c:1},e:{r:5,c:2}},]

