先分析一下需求:原本的需求就是简单的一句话,“前端做一个离线工具可以批量处理图片”,关键点前端,离线, 批量, 图片
- 前端做 = 肯定需要node,处理问价。之前对node一窍不通
- 离线 = 需要用的可以生成客户端的东西
- 批量 = 可能会有很多
- 图片 = 是否需要压缩
接下来逐一解决,先来处理关键点,实际离线不离线的主重要重要的是能够批量的把图片给处理了。所以我们先来解决如何使用原生js
结合node
来处理文件与文件夹
1: 获取文件夹路径
批量处理图片,有两种方式,第一种一次性选中多张图片进行处理,第二种处理文件夹。我需要处理的图片大概有几千张所以选择第二种,因为获取文件夹用到了Electron
的API
,所以这个先跳过。如果你对Electron
没有了解过,建议你可以先学习一下,这里推荐一个博主技术胖,博客地址,讲的详细且易懂,而且能学到很多新知识
2:读取文件夹里内容
假设我们已经拿到了文件夹路径,那就需要读取改路径下的文件了,这里就有用到node.js
的fs
模块
const fs = require("fs");
let arr = fs.readdirSync(文件夹路径); // 读取该路径下所有文件,如下图
复制代码
注意:这里我们获取到的是改文件夹下所有文件,包括文件夹,如果需要继续处理文件夹下的文件夹,那么就需要判断是否为文件夹,然后使用递归处理,如下
fs.statSync(filePath).isDirectory() // 判断此路径是否为文件夹
path.extname // 返回path路径文件扩展名
复制代码
function readfile(dir) {
let arr = fs.readdirSync(dir);
console.log(arr)
arr.forEach((item) => {
let filePath = path.join(dir, item); // 拼接成完成的路径
if (path.extname(item) == ".png") {
} else if (path.extname(item) == ".jpg") {
} else if (fs.statSync(filePath).isDirectory()) {
readfile(filePath);
}
}
复制代码
3:修改数据类型
上传文件,就需要根据文件路径读取文件,一般上传图片的格式为Blob
,那我们需要根据文件路径读取相对应的文件并把数据格式转换成Blob
类型的。
注意:读取文件需要文件完成路径,在第二步的时候使用filePath = path.join(dir, item)
拼接完成路径
fs.readFile(文件路径, (err, data) => {
if (err) throw err;
let blobFile = new File([data], 文件名, type: "image/jpg" }
});
复制代码
其中fs.readFile
返回的data
数据格式是Buffer
格式的,就需要再把Buffer
转换成Blob
的数据类型,如下图,看到这种格式是不是就很亲切了
这个时候拿到这个数据就可以去调用上传接口了
4:上传文件
这里用的XMLHttpRequest
进行文件上传,至于为什么用这个,因为我整个项目都是用原生去写的,可能你也忘了XMLHttpRequest
如何使用,那么一起温故一下吧
function uploadImgFromPastePro(frontfile, backfile) {
return new Promise((success, error) => {
var formData = new FormData();
formData.append("front", frontfile);
formData.append("back", backfile);
var xhr = new XMLHttpRequest();
xhr.open("POST", `你的url`);
xhr.onload = function () {
console.log(xhr.readyState);
if (xhr.readyState === 4) {
if (xhr.status === 200) {
var data = JSON.parse(xhr.responseText);
console.log(data);
if (data.code === 200) {
success(data);
} else {
success(data);
}
} else {
error(xhr.statusText);
}
}
};
xhr.onerror = function (e) {
console.log(xhr.statusText);
error(xhr.statusText);
};
xhr.send(formData);
});
}
复制代码
到了这一步,我们熟悉的js
已经结束了,接下来就需要结合Electron
,用来选取文件夹,我们回到第一步,默认你们已经跟着技术胖学习了Electron
1:获取文件夹路径
我们需要使用Electron
的dialog
模块,那么先引入
const { dialog } = require("electron").remote;
复制代码
具体的参数我这里就不介绍了,可以去W3C看看,文档地址
openBtn.onclick = function () {
jpgArray = [];
pathArr = [];
isFilePath = "";
dialog
.showOpenDialog({
properties: ["openDirectory"],
})
.then((result) => {
console.log(result);
})
.catch((err) => {
console.log(err);
});
};
复制代码
代码如上:其中的result
就是获取到的文件夹路径
5:结束语
刚拿到需求的时候心里很是排斥的,因为需求使用的electron
是我能力之外的,所以对这个需求自己是胆怯的,但是随着自己慢慢的深入,发现探索未知是很有成就感的。做完也很庆幸自己又了解到了一个新的东西,顺便学了点node.js
的使用。
6:附带,node.js压缩图片
本来是要去我使用node.js
压缩图片,压缩完后再传给服务端,但是在我实现的过程中踩了很多坑,最后结果是放弃了前端解决,服务端进行压缩。
因为坑我没有淌过去,所以就简单的说一下自己用了那几个压缩组件
首先压缩jpg
类型的使用的是images
,这里遇到的坑是,当图片大于1M的时候,electron
就会崩掉,错误也没有抛出
另外一个:imagemin
,这个实际挺好用的,但是安装的时候属实难受,这里建议使用cnpm进行安装,否则就会有问题,也可能是我科学上网的工具不行
网上有建议使用imagemin@5.0.1
,安装是可以成功,但是压缩没有效果
这里需要注意的是:这个imagemin
需要结合其他组件一起使用,一下插件都建议使用cnpm
安装,否则很容安装失败,使用方法如下
"imagemin-jpegtran": "^7.0.0",
"imagemin-mozjpeg": "^9.0.0",
"imagemin-pngquant": "^9.0.1"
复制代码
imagemin([文件路径], {
destination: 输出路径,
use: [imageminMozjpeg()],
plugins: [
imageminJpegtran(), // 这里是胡乱写的因为我也不知道到底有没有起作用
imageminMozjpeg(), // 这里是胡乱写的因为我也不知道到底有没有起作用
imageminPngquant({
quality: [0.3, 0.6],
}),
],
})
.then(() => {
})
.catch((err) => {
});
复制代码
这里的坑我没有踩过去,有需要的话做好心理准备