======================

FileSaver.js(保存文件)

保存文件:https://github.com/eligrey/FileSaver.js

安装

安装到项目

  1. npm install file-saver --save

或者cdn引入

  1. <script src="./public/cdn/file/FileSaver.js"></script>

引入

如果是npm安装,使用时可以通过import引入

  1. import { saveAs } from "file-saver";

如果是cdn引入,会给你的全局对象(浏览器就是window)添加一个saveAs函数,直接用

  1. window.saveAs

使用

主要是通过函数saveAs( Blob/File/Url, 文件名 , [选项]) 进行操作
选项只有:{ autoBom: true },转换成Unicode,只有blob type 为 charset=utf-8 有效。

如通过二进制格式blob,保存成文件

  1. var blob = new Blob(["Hello, world!"], {type: "text/plain;charset=utf-8"});
  2. saveAs(blob, "hello world.txt");//其他格式也可以,比如表格xlsx

保存成图片

  1. var canvas = document.getElementById("my-canvas")
  2. canvas.toBlob(function(blob) {
  3. saveAs(blob, "pretty image.png");
  4. });
  5. // 或
  6. FileSaver.saveAs("https://httpbin.org/image", "image.jpg");

=======================

ExcelJS(强大,但慢)

https://github.com/exceljs/exceljs

安装

无需安装,外部引入即可
在index.htm内引入

  1. <script src="./public/cdn/file/FileSaver.js"></script>
  2. <script src="./public/cdn/file/exceljs.min.js"></script>

导出xlsx

  1. //1、表格数据为json
  2. let jsonData = [
  3. {id:1,name:'yjl',sex:'男'},
  4. {id:2,name:'xj',sex:'女'},
  5. ];
  6. //2、创建工作簿
  7. let workbook = new ExcelJS.Workbook();
  8. //3、工作簿加入工作表
  9. let worksheet = workbook.addWorksheet('sheet1');
  10. //4、定义列
  11. worksheet.columns = [
  12. { header: 'Id', key: 'id', width: 10 },
  13. { header: 'Name', key: 'name', width: 32 },
  14. { header: 'Sex', key: 'sex', width: 10 }
  15. ];
  16. //5、根据数据,给行赋值
  17. for (let r in jsonData) {
  18. worksheet.addRow(jsonData[r]);
  19. }
  20. //6、导出
  21. workbook.xlsx.writeBuffer()
  22. .then((data) => {
  23. const buff = new Blob([data],{type: "text/plain;charset=utf-8"});
  24. saveAs(buff, "hello world.xlsx");
  25. }).catch((err)=>{
  26. console.log("err: ",err);
  27. })

导入

Vue3.0 版本 + TS 版本(不需要TS的话可以自己去掉 lang=’ts’)

  1. <template>
  2. <div>
  3. <!-- 弹出选择文件按钮 -->
  4. <input
  5. id="importBtn"
  6. ref="importBtn"
  7. type="file"
  8. accept=".xlsx,.xls"
  9. style="display: none"
  10. @change="importSelect"
  11. />
  12. <!-- 显示的假按钮 -->
  13. <a-button type="primary" @click="importBtnClick" v-bind="props.btnProps">
  14. {{ props.btnText }}
  15. </a-button>
  16. </div>
  17. </template>
  18. <script lang='ts'>
  19. export default {
  20. inheritAttrs: false,
  21. name: "importBtn"
  22. }
  23. </script>
  24. <script setup lang='ts'>
  25. import { ref } from "vue"
  26. import ExcelJS from "exceljs"
  27. import utils from '@/utils'
  28. /** 父组件传入参数 */
  29. const props = defineProps({
  30. /** 按钮 文本 */
  31. btnText: {
  32. type: String,
  33. default: "导入Excel"
  34. },
  35. /** 文件大小判断, 单位MB ,0为不限制 */
  36. fileSizeLimit:{
  37. type:Number,
  38. default:0
  39. },
  40. /** 按钮 属性 */
  41. btnProps: {
  42. default: {}
  43. }
  44. })
  45. const emits = defineEmits(["selectFile"])
  46. /** 显示的假按钮 点击时,触发选择文件 */
  47. const importBtnClick = () => {
  48. // 重要,重置已选取的路径,因为触发导入事件是通过change改变触发,如果不重置路径,那么重复选同一个文件时会不执行后续代码
  49. let impBtn = document.getElementById("importBtn") as HTMLInputElement | null
  50. if (impBtn) {
  51. impBtn.value = ""
  52. impBtn.click()
  53. }
  54. }
  55. // 导入按钮事件
  56. function importSelect() {
  57. // 1、通过input打开选择文件窗口,获取文件信息
  58. let readFile = document.getElementById("importBtn") as HTMLInputElement
  59. // 2、判断用户是否选择了文件
  60. if (readFile?.files && readFile.files[0]) {
  61. // console.log("用户选择了文件", readFile.files[0])
  62. let tempReadFile = readFile.files[0]
  63. // 判断选择的文件类型
  64. if (tempReadFile.type != "application/vnd.ms-excel" && tempReadFile.type as any != "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet") {
  65. utils.notice.showErrorMessage("选择的文件类型不正确")
  66. return
  67. }
  68. // 判断文件大小限制
  69. if ( props.fileSizeLimit !=0 && tempReadFile.size>props.fileSizeLimit) {
  70. utils.notice.showErrorMessage(`选择的文件大小超过了 ${props.fileSizeLimit}MB `)
  71. return
  72. }
  73. // 3、创建工作簿
  74. let workbookRead = new ExcelJS.Workbook()
  75. // 4、使用JS的web API FileReader 读取文件信息
  76. let reader = new FileReader()
  77. // 5、设定FileReader读取时的操作,调用读操作(如readAsArrayBuffer)时就会执行这段
  78. reader.onload = function (event) {
  79. //读取时是传入读取的事件,事件里面.target.result就是用户选择文件的内容
  80. let fileData = event?.target?.result as ArrayBuffer
  81. if (fileData) {
  82. //7、用工作簿读取文件内容,通过ArrayBuffer的方式读取
  83. workbookRead.xlsx.load(fileData).then((res) => {
  84. // console.log("res: ", res)
  85. // 把数据提交父组件
  86. emits("selectFile",res)
  87. })
  88. }
  89. }
  90. // 6、调用FileReader读取文件,用readAsArrayBuffer的方法,把内容变成ArrayBuffer
  91. reader.readAsArrayBuffer(readFile.files[0])
  92. } else {
  93. utils.notice.showErrorMessage("选择文件异常",2)
  94. console.log("readFile.files",readFile?.files)
  95. }
  96. }
  97. </script>
  98. <style lang='less'>
  99. </style>

image.png

工作簿 WorkBook

基本文件信息

  1. //文件信息
  2. workbook.creator = 'Me'; //创建人
  3. workbook.lastModifiedBy = 'Her'; //最后修改人
  4. workbook.created = new Date(1985, 8, 30); //创建时间
  5. workbook.modified = new Date(); //修改时间
  6. workbook.lastPrinted = new Date(2016, 9, 27); //最后打印时间
  7. workbook.properties.date1904 = true;// 将工作簿日期设置为 1904 年日期系统,默认是用1900年

添加、删除工作表

  1. const sheet = workbook.addWorksheet('My Sheet'); //把工作表sheet添加到工作簿workbook,并且命名为My Sheet
  2. workbook.removeWorksheet(sheet.id); //删除工作表

工作表 WorkSheet

列 column

行 row

单元格 cell

表格 table

其他设置、样式

=======================

SheetJS(简单,快速)

https://github.com/SheetJS/sheetjs (要用到保存文件)
文档:https://docs.sheetjs.com/docs

引入模块

推荐通过npm安装

  1. npm install --save https://cdn.sheetjs.com/xlsx-0.18.9/xlsx-0.18.9.tgz

导出表格

  1. //1、假设表格数据为json
  2. let jsonData = [
  3. {id:1,name:'叶杰麟',sex:'man'},
  4. {id:2,name:'xj',sex:'women'},
  5. ];
  6. //2、创建工作表Sheet
  7. let sheet = XLSX.utils.json_to_sheet(jsonData);
  8. //3、创建工作簿workBook
  9. let wb = XLSX.utils.book_new();
  10. //4、把工作表Sheet,放入工作簿workBook内
  11. XLSX.utils.book_append_sheet(wb, sheet, 'sheet1')
  12. //5、将工作簿workBook 和 导出选项一起写入
  13. let wbout = XLSX.write(wb, {type: 'binary'})
  14. //6、创建一个String 转换成 ArrayBuffer的函数
  15. function StringToArrayBuffer(string) {
  16. let buf = new ArrayBuffer(string.length);
  17. let view = new Uint8Array(buf);
  18. for (let i = 0; i != string.length; ++i) {
  19. view[i] = string.charCodeAt(i) & 0xff;
  20. }return buf;
  21. }
  22. //7、把 workBook和导出选项 转换成 Blob
  23. let blob = new Blob([StringToArrayBuffer(wbout)], {type: "text/plain;charset=utf-8"});
  24. //8、导出
  25. saveAs(blob, "hello world.xlsx");//其他格式也可以,比如表格xlsx

image.png

导入表格

导入表格按钮示例,点击后弹出选择文件对话框,选择文件后通过emits(selectFile) 把结果返回给父组件使用

  1. <template>
  2. <div>
  3. <!-- 弹出选择文件按钮 -->
  4. <input
  5. id="importBtn"
  6. ref="importBtn"
  7. type="file"
  8. accept=".xls,.xlsx"
  9. style="display: none"
  10. @change="importSelect"
  11. />
  12. <!-- 显示的假按钮 -->
  13. <a-button type="primary" @click="importBtnClick" v-bind="props.btnProps">
  14. {{ props.btnText }}
  15. </a-button>
  16. </div>
  17. </template>
  18. <script lang='ts'>
  19. export default {
  20. inheritAttrs: false,
  21. name: "importBtn"
  22. }
  23. </script>
  24. <script setup lang='ts'>
  25. import { ref } from "vue"
  26. import * as XLSX from 'xlsx'
  27. import utils from "@/utils"
  28. /** 父组件传入参数 */
  29. const props = defineProps({
  30. /** 按钮 文本 */
  31. btnText: {
  32. type: String,
  33. default: "导入Excel"
  34. },
  35. /** 文件大小判断, 单位MB ,0为不限制 */
  36. fileSizeLimit: {
  37. type: Number,
  38. default: 0
  39. },
  40. /** 按钮 属性 */
  41. btnProps: {
  42. default: {}
  43. }
  44. })
  45. const emits = defineEmits(["selectFile","handleLoading"])
  46. /** 显示的假按钮 点击时,触发选择文件 */
  47. const importBtnClick = () => {
  48. // 重要,重置已选取的路径,因为触发导入事件是通过change改变触发,如果不重置路径,那么重复选同一个文件时会不执行后续代码
  49. let impBtn = document.getElementById("importBtn") as HTMLInputElement | null
  50. if (impBtn) {
  51. impBtn.value = ""
  52. impBtn.click()
  53. }
  54. }
  55. // 导入按钮事件
  56. function importSelect() {
  57. emits("handleLoading",true)
  58. // 1、通过input打开选择文件窗口,获取文件信息
  59. let readFile = document.getElementById("importBtn") as HTMLInputElement
  60. // 2、判断用户是否选择了文件
  61. if (readFile?.files && readFile.files[0]) {
  62. // console.log("用户选择了文件", readFile.files[0])
  63. let tempReadFile = readFile.files[0]
  64. // 判断选择的文件类型
  65. if (
  66. tempReadFile.type != "application/vnd.ms-excel" &&
  67. (tempReadFile.type as any) !=
  68. "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"
  69. ) {
  70. utils.notice.showErrorMessage("选择的文件类型不正确")
  71. emits("handleLoading",false)
  72. return
  73. }
  74. // 判断文件大小限制
  75. if (props.fileSizeLimit != 0 && tempReadFile.size > props.fileSizeLimit) {
  76. utils.notice.showErrorMessage(
  77. `选择的文件大小超过了 ${props.fileSizeLimit}MB `
  78. )
  79. emits("handleLoading",false)
  80. return
  81. }
  82. // 3、使用JS的web API FileReader 读取文件信息
  83. let reader = new FileReader()
  84. // 4、设定FileReader读取时的操作,调用读操作(如readAsArrayBuffer)时就会执行这段
  85. reader.onload = function (event) {
  86. //读取时是传入读取的事件,事件里面.target.result就是用户选择文件的内容
  87. let fileData = event?.target?.result as ArrayBuffer
  88. if (fileData) {
  89. // 7、用sheetJS 的方式读取内容
  90. let res = XLSX.read(fileData)
  91. console.log('导入按钮的res',res)
  92. emits("selectFile", res)
  93. emits("handleLoading",false)
  94. }
  95. }
  96. // 5、调用FileReader读取文件,用readAsArrayBuffer的方法,把内容变成ArrayBuffer
  97. reader.readAsArrayBuffer(readFile.files[0])
  98. } else {
  99. utils.notice.showErrorMessage("选择文件异常", 2)
  100. // console.log("readFile.files", readFile?.files)
  101. emits("handleLoading",false)
  102. }
  103. }
  104. </script>
  105. <style lang='less'>
  106. </style>

表格选项

单元格 Cell

单元格对象通过sheet[‘A1’]表示,如下图:
image.png

其他设置中:
单元地址对象存储为{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 (.Target
holds link, .Tooltip
is tooltip)
s 单元格样式
e错误值 错误说明
0x00 #NULL!
0x07 #DIV/0!
0x0F #VALUE!
0x17 #REF!
0x1D #NAME?
0x24 #NUM!
0x2A #N/A
0x2B #GETTING_DATA

工作表 sheet

打印边距 margins

  1. //2、创建工作表Sheet
  2. let sheet = XLSX.utils.json_to_sheet(jsonData);
  3. //设置打印边距,左边距、右边距、上边距、下边距、页眉、页脚
  4. sheet["!margins"]={left:0, right:0, top:0,bottom:0,header:0,footer:0};

image.png

单元格合并 merges

存放一些单元格合并信息,是一个数组。
每个数组由包含s和e构成的对象组成,s表示开始start,e表示结束end,r表示行row,c表示列colmn,从0开始的;

  1. //2、创建工作表Sheet
  2. let sheet = XLSX.utils.json_to_sheet(jsonData);
  3. sheet['!merges']=[
  4. {
  5. s:{r:4,c:1},
  6. e:{r:5,c:2}
  7. },
  8. ]

image.png