注册
vue

让你用最简单的方式使用Vue2 + Web Worker + js-xlsx 解析excel数据

最简单的应该就是 C V 大法了吧!!!


cv.jpg


说明


本文重点在于实现功能,没有过多去关注其他。 就想使用的话直接cv到自己的项目即可,想深入学习下边也有官方网址自行查看咯🍺


SheetJS出品的js-xlsx是一款非常方便的只需要纯JS即可读取和导出excel的工具库,功能强大,支持格式众多,支持xls、xlsx、ods(一种OpenOffice专有表格文件格式)等十几种格式。本文以xlsx格式为例。github:github.com/SheetJS/she…


为什么使用Web Worker呢?为了加快解析速度,提高用户体验度🤡。Web Worker具体介绍看阮老师的博客就好😀
Web Worker 使用教程 - 阮一峰的网络日志


本文配套demo仓库:gitee.com/ardeng/work…


效果演示


演示效果


上代码


HTML


普普通通、简简单单的element ui 上传组件


<el-upload
ref="input"
action="/"
:show-file-list="false"
:auto-upload="false"
:on-change="importExcel"
type="file"
>
<el-button type="primary">上传</el-button>
</el-upload>

JS部分


先来个无 Web Worker 版


Worker 线程一旦新建成功,就会始终运行,不会被主线程上的活动(比如用户点击按钮、提交表单)打断。这样有利于随时响应主线程的通信。但是,这也造成了 Worker 比较耗费资源,不应该过度使用,而且一旦使用完毕,就应该关闭。


Web Worker 有以下几个使用注意点。



  1. 同源限制 分配给 Worker 线程运行的脚本文件,必须与主线程的脚本文件同源。
  2. DOM 限制 Worker 线程所在的全局对象,与主线程不一样,无法读取主线程所在网页的 DOM 对象,也无法使用documentwindowparent这些对象。但是,Worker 线程可以navigator对象和location对象。
  3. 通信联系 Worker 线程和主线程不在同一个上下文环境,它们不能直接通信,必须通过消息完成。
  4. 脚本限制 Worker 线程不能执行alert()方法和confirm()方法,但可以使用 XMLHttpRequest 对象发出 AJAX 请求。
  5. 文件限制 Worker 线程无法读取本地文件,即不能打开本机的文件系统(file://),它所加载的脚本,必须来自网络。

由于以上的限制,所以不想搞Worker也可以。 直接解析文件对象 转换数据即可。


importExcel(file) {
// 验证文件是否为excel
if (!/\.(xlsx|xls|csv)$/.test(file.name)) {
alert("格式错误!请重新选择")
return
}
this.fileToExcel(file).then(tabJson => {
// 这里拿到excel的数据
console.log(tabJson)
})
},
// excel数据转为json数组
fileToExcel(file) {
// 不使用 Promise 也可以 只是把读文件做成异步更合理
return new Promise(function (resolve, reject) {
const reader = new FileReader()
reader.onload = function (e) {
// 拿到file数据
const result = e.target.result
// XLSX 解析的配置 type: 'binary' 必写
const excelData = XLSX.read(result, { type: 'binary' })
// 注意要加 { header: 1 }, 此配置项 可生成二维数组
const data = XLSX.utils.sheet_to_json(excelData.Sheets[excelData.SheetNames[0]],
{ header: 1 }) //! 读取去除工作簿中的数据
resolve(data)
}
// 调用方法 读取二进制字符串
reader.readAsBinaryString(file.raw)
})
}

Web Worker版


想用Worker 一些前置工作是必不可少的



  1. 下载 worker-loader

npm i -D worker-loader


  1. vue.config.js中配置loader

// 设置解析以worker.js 结尾的文件使用worker-loader 解析
chainWebpack: config => {
config.module.rule('worker')
.test(/\.worker\.js$/)
.use('worker-loader')
.loader('worker-loader')
.options({ inline: 'fallback' })
}

正式进入使用Web Worker


封装一下 Web Worker 命名规则如下:xxx.worker.js


下面代码中,self代表子线程自身,即子线程的全局对象。


// src\utils\excel.worker.js

import XLSX from 'xlsx'

/**
* 处理错误的函数 主线程可以监听 Worker 是否发生错误。
* 如果发生错误,Worker 会触发主线程的`error`事件。
*/
const ERROR = () => {
// 发送错误信息
self.postMessage({ message: 'error', data: [] })

// `self.close()`用于在 Worker 内部关闭自身。
self.close()
}

// 错误处理
self.addEventListener('error', (event) => {
ERROR()

// 输出错误信息
console.log('ERROR: Line ', event.lineno, ' in ', event.filename, ': ', event.message)
})

/**
* @description: Worker 线程内部需要有一个监听函数,监听`message`事件。 工作线程接收到主线程的消息
* @param {object} event event.data 获取到主线程发送过来的数据
*/
self.addEventListener('message', async (event) => {
// 向主线程发送消息
// postMessage(event.data);

// 解析excel数据
parsingExcel(event.data)
}, false)

/**
* @description: 解析excel数据
* @param {object} data.excelFileData 文件数据
* @param {object} data.config 配置信息
*/
const parsingExcel = (data) => {
try {
// 注意 { header: 1 }, 此配置项 可生成二维数组
const { excelFileData, config = { header: 1 } } = data

// 创建实例化对象
const reader = new FileReader()

// 处理数据
reader.onload = function (e) {
// 拿到file数据
const result = e.target.result;
const excelData = XLSX.read(result, { type: 'binary' })
const data = XLSX.utils.sheet_to_json(excelData.Sheets[excelData.SheetNames[0]], config) //! 读取去除工作簿中的数据

// 发送消息
self.postMessage({ message: 'success', data })
};
// 调用方法 读取二进制字符串
reader.readAsBinaryString(excelFileData.raw);
} catch (err) {
ERROR()
console.log('解析excel数据时 catch到的错误===>', err)
}
}

使用


引入文件


import Worker from '@/utils/excel.worker.js'

业务相关的逻辑


importExcel(file) {
if (!/\.(xlsx|xls|csv)$/.test(file.name)) {
alert("格式错误!请重新选择")
return;
}

// 创建实列
const worker = new Worker()

// 主线程调用`worker.postMessage()`方法,向 Worker 发消息
worker.postMessage({
excelFileData: file,
config: { header: 1 }
})

// 主线程通过`worker.onmessage`指定监听函数,接收子线程发回来的消息
worker.onmessage = (event) => {
const { message, data } = event.data
if (message === 'success') {
// data是个二维数组 表头在上边
console.log(data)
// Worker 完成任务以后,主线程就可以把它关掉。
worker.terminate()
}
}
}

可能遇到的问题



  1. npm run dev 启动不了,并且 webpack 报错:检查下 webpack worker-loader 的版本。
  2. 控制台报错包含 not a function 或 not a constructor:检查下 webpck 配置。最好是查看英文文档 webpack,因为中文文档更新不及时。
  3. 控制台报错 window is not defined:改成 self 试试。参考 Webpack worker-loader - import doesn’t work


链接:https://juejin.cn/post/7010046891480055815

0 个评论

要回复文章请先登录注册