最近在做一个压缩zip,又解压zip的功能。需求是这样的:如下图所示,
1、红色框框里都是需要打包的东西,需要2个zip包,一个android,一个ios,点击两个绿色按钮开始压缩;
2、压缩包zip里面解压后是1个大文件夹,大的文件夹里面包含4个文件夹,分别为1个u3d(ios或android)模型文件夹(u3d)、1个背景图文件夹(bg)、1个人物图文件夹(gif)和1个展会切换图文件夹(switchover),如图二显示;
3、bg文件夹和gif文件夹里面的图片是根据蓝色框框中的数量动态改变的,需要全部图片上传后才可压缩;
4、把大的文件夹压缩成zip文件后,上传到oss,把得到的路径在绿色按钮旁边的input框中显示,并在保存的时候传给服务端;
5、编辑的时候再次点开,服务端会把zip的地址返给前端,此时,前端根据拿到的地址,解压,把文件依次渲染在页面上,如图三所示
下面是实现思路:
1、首先,new一个全局zip实例a_zipBar,再利用这个实例新建一个全局文件夹变量a_folder(一式两份,a代表android,i代表ios)
2、其次,上传u3d模型的时候,用a_folder文件夹新建一个u3d文件夹;
3、其次,上传背景图的时候,用a_folder文件夹新建一个bg文件夹,把图片一次添加进去;
4、其次,上传人物图的时候,用a_folder文件夹新建一个gif文件夹,把图片一次添加进去;
5、再次,上传展会切换图的时候,用a_folder文件夹新建一个switchover文件夹;
6、最后,压缩a_folder文件夹,格式为zip,上传
下面是实现过程,压缩较为简单,解压过程较复杂
1、首先是根据蓝色框框内的数量,动态改变图片的数量
watch: {
"currentRow.diamondCount"(newValue, oldValue) {
//监听钻石展位
newValue ? "" : (newValue = 0);
oldValue ? "" : (oldValue = 0);
this.getImageList(this.currentRow.diamondCount, "diamondCount", newValue, oldValue, true);
},
"currentRow.platinumCount"(newValue, oldValue) {
//监听铂金展位
newValue ? "" : (newValue = 0);
oldValue ? "" : (oldValue = 0);
this.getImageList(this.currentRow.platinumCount, "platinumCount", newValue, oldValue, false);
},
"currentRow.goldCount"(newValue, oldValue) {
//监听黄金展位
newValue ? "" : (newValue = 0);
oldValue ? "" : (oldValue = 0);
this.getImageList(this.currentRow.goldCount, "goldCount", newValue, oldValue, false);
}
},
//新增展会图片列表数据的添加与删除
getImageList(inputLen, type, newValue, oldValue) {
let diamondCount = this.currentRow.diamondCount;
let platinumCount = this.currentRow.platinumCount;
let goldCount = this.currentRow.goldCount;
let diffCount = Math.abs(newValue - oldValue);
// array.splice(2, 0, "three"); // 拼接函数(索引位置, 要删除元素的数量(0为不删除), 新增的元素)
if (newValue > oldValue) {
//
if (type === "diamondCount") {
for (let i = 0; i < diffCount; i++) {
this.imageList.splice(oldValue + i, 0, {bgImage: "", personImage: ""});
}
} else if (type === "platinumCount") {
for (let i = 0; i < diffCount; i++) {
this.imageList.splice(diamondCount + oldValue + i, 0, {bgImage: ""});
}
} else {
for (let i = 0; i < diffCount; i++) {
this.imageList.splice(diamondCount + platinumCount + oldValue + i, 0, {bgImage: ""});
}
}
} else if (newValue < oldValue) {
// array.splice(2, 1);
if (type === "diamondCount") {
for (let i = 0; i < diffCount; i++) {
this.imageList.splice(oldValue - i - 1, 1);
}
} else if (type === "platinumCount") {
for (let i = 0; i < diffCount; i++) {
this.imageList.splice(diamondCount + oldValue - i - 1, 1);
}
} else {
for (let i = 0; i < diffCount; i++) {
this.imageList.splice(diamondCount + platinumCount + oldValue - i - 1, 1);
}
}
}
},
2、其次,上传u3d模型、背景图、人物图和展会切换图
//上传展会切换图
uploadSwitch(event) {
let file = event.file;
let fileType = 1; // 图片1,音频2,视频3,文件4
let str = file.type.split("/")[1];
uploadApi.upLoad.uploader(file, fileType).then((res) => {
if (this.title === "新增") {
this.currentRow.switchover = res.url;
a_U3d.folder("switchover").file("switchover." + str, file, {base64: true});
i_U3d.folder("switchover").file("switchover." + str, file, {base64: true});
} else if (this.title === "编辑") {
this.currentRow.switchover = res.url;
this.$refs.formRef.$forceUpdate();
for (let i in edit_i_U3d.files) {
let imgName = edit_i_U3d.files[i].name; //获取文件名
let imageIndex = imgName.lastIndexOf("\/"); //截取字符串最后一个/后面的所有字符
imgName = imgName.substring(imageIndex + 1, imgName.length);
if (imgName === "switchover.png") {
//如果文件名一致,则替换掉原有图片
delete edit_i_U3d.files[i];
edit_i_U3d
.folder("i_shanghai_map")
.folder("switchover")
.file("switchover.png", event.file, {base64: true});
}
}
for (let i in edit_a_U3d.files) {
let imgName = edit_a_U3d.files[i].name; //获取文件名
let imageIndex = imgName.lastIndexOf("\/"); //截取字符串最后一个/后面的所有字符
imgName = imgName.substring(imageIndex + 1, imgName.length);
if (imgName === "switchover.png") {
//如果文件名一致,则替换掉原有图片
delete edit_a_U3d.files[i];
edit_a_U3d
.folder("a_shanghai_map")
.folder("switchover")
.file("switchover.png", event.file, {base64: true});
}
}
}
});
},
// U3D资源包
compressZip(file, type) {
if (this.title === "新增") {
if (type === "ios") {
i_U3d.folder("u3d").file("u3d", file);
} else {
a_U3d.folder("u3d").file("u3d", file);
}
} else if (this.title === "编辑") {
for (let i in edit_i_U3d.files) {
let imgName = edit_i_U3d.files[i].name; //获取文件名
let imageIndex = imgName.lastIndexOf("\/"); //截取字符串最后一个/后面的所有字符
imgName = imgName.substring(imageIndex + 1, imgName.length);
if (imgName === "u3d") {
//如果文件名一致,则替换掉原有u3d模型
delete edit_a_U3d.files[i];
edit_i_U3d.folder("u3d").file("u3d", file);
}
}
for (let i in edit_a_U3d.files) {
let imgName = edit_a_U3d.files[i].name; //获取文件名
let imageIndex = imgName.lastIndexOf("\/"); //截取字符串最后一个/后面的所有字符
imgName = imgName.substring(imageIndex + 1, imgName.length);
if (imgName === "u3d") {
//如果文件名一致,则替换掉原有u3d模型
delete edit_a_U3d.files[i];
edit_a_U3d.folder("u3d").file("u3d", file);
}
}
}
},
// 上传背景图或展厅人物图
onClickUploadImageHandle(event, index, type) {
let file = event.file;
let fileType = 1; // 图片1,音频2,视频3,文件4
let suffix = file.name.split(".")[1]; //图片后缀
uploadApi.upLoad.uploader(file, fileType).then((res) => {
if (type === "bgImage") {
if (this.title === "新增") {
this.imageList[index].bgImage = res.url;
a_U3d.folder("bg").file(index + 1 + "." + suffix, event.file, {base64: true});
i_U3d.folder("bg").file(index + 1 + "." + suffix, event.file, {base64: true});
} else if (this.title === "编辑") {
this.$set(this.imageList[index], "bgImage", res.url);
for (let i in edit_i_U3d.files) {
let imgName = edit_i_U3d.files[i].name; //获取文件名
let imageIndex = imgName.lastIndexOf("\/"); //截取字符串最后一个/后面的所有字符
imgName = imgName.substring(imageIndex + 1, imgName.length);
if (imgName === index + 1 + ".png") {
//如果文件名一致,则替换掉原有图片
delete edit_i_U3d.files[i];
edit_i_U3d
.folder("i_shanghai_map")
.folder("bg")
.file(index + 1 + "." + suffix, event.file, {base64: true});
}
}
for (let i in edit_a_U3d.files) {
let imgName = edit_a_U3d.files[i].name; //获取文件名
let imageIndex = imgName.lastIndexOf("\/"); //截取字符串最后一个/后面的所有字符
imgName = imgName.substring(imageIndex + 1, imgName.length);
if (imgName === index + 1 + ".png") {
//如果文件名一致,则替换掉原有图片
delete edit_a_U3d.files[i];
edit_a_U3d
.folder("a_shanghai_map")
.folder("bg")
.file(index + 1 + "." + suffix, event.file, {base64: true});
}
}
}
} else {
if (this.title === "新增") {
this.imageList[index].personImage = res.url;
a_U3d.folder("gif").file(index + 1 + ".gif", event.file, {base64: true});
i_U3d.folder("gif").file(index + 1 + ".gif", event.file, {base64: true});
} else if (this.title === "编辑") {
this.$set(this.imageList[index], "personImage", res.url);
this.$refs.formRef.$forceUpdate();
for (let i in edit_i_U3d.files) {
let imgName = edit_i_U3d.files[i].name; //获取文件名
let imageIndex = imgName.lastIndexOf("\/"); //截取字符串最后一个/后面的所有字符
imgName = imgName.substring(imageIndex + 1, imgName.length);
if (imgName === index + 1 + ".gif") {
//如果文件名一致,则替换掉原有图片
delete edit_i_U3d.files[i];
edit_i_U3d
.folder("i_shanghai_map")
.folder("gif")
.file(index + 1 + "." + suffix, event.file, {base64: true});
}
}
for (let i in edit_a_U3d.files) {
let imgName = edit_a_U3d.files[i].name; //获取文件名
let imageIndex = imgName.lastIndexOf("\/"); //截取字符串最后一个/后面的所有字符
imgName = imgName.substring(imageIndex + 1, imgName.length);
if (imgName === index + 1 + ".gif") {
//如果文件名一致,则替换掉原有图片
delete edit_a_U3d.files[i];
edit_a_U3d
.folder("a_shanghai_map")
.folder("gif")
.file(index + 1 + "." + suffix, event.file, {base64: true});
}
}
}
}
});
},
压缩:
<el-button @click="handleExpress("a_shanghai_map")">点击压缩Android</el-button>
<el-button @click="handleExpress("i_shanghai_map")">点击压缩IOS</el-button>
<script>
import JSZip from "jszip";
import {getOssToken} from "@/api/baseInfo";
//新增
let a_zip = new JSZip();
let i_zip = new JSZip();
let a_U3d = a_zip.folder("a_shanghai_map");
let i_U3d = i_zip.folder("i_shanghai_map");
// 编辑
let edit_a_zip = new JSZip();
let edit_i_zip = new JSZip();
let edit_a_U3d = a_zip.folder("a_shanghai_map");
let edit_i_U3d = i_zip.folder("i_shanghai_map");
export default {
data() {
return {}
},
methods: {
//压缩
handleExpress(name) {
if (this.resourceLen && this.isBgImage && this.isPersonImage) {
if (name === "i_shanghai_map") {
this.isPercentShow.ios = true;
} else {
this.isPercentShow.android = true;
}
let type = "";
if (this.title === "新增") {
type = name === "i_shanghai_map" ? i_zip : a_zip;
} else if (this.title === "编辑") {
type = name === "i_shanghai_map" ? edit_i_U3d : edit_a_U3d;
}
let timestamp = new Date().valueOf(); //时间戳
type.generateAsync({type: "blob"}).then((blob) => {
let files = new File([blob], timestamp + "-" + name, {type: "zip"});
this.uploader(blob, files, name).then((res) => {
let url = aliOssUrl + res.name;
if (name === "i_shanghai_map") {
this.currentRow.iOSResource = url;
this.currentRow.iOSResourceSize = files.size;
this.isPercentShow.ios = false;
} else {
this.currentRow.androidResource = url;
this.currentRow.androidResourceSize = files.size;
this.isPercentShow.android = false;
}
});
});
} else {
this.$message.warning("请完善资源包信息");
}
},
//oss分片上传
uploader(blob, files, name) {
return getOssToken({type: 4}).then((res) => {
const Oss = require("ali-oss");
const client = new Oss({
region: res.region,
secure: true,
accessKeyId: res.accessKeyId,
accessKeySecret: res.accessKeySecret,
stsToken: res.securityToken,
bucket: res.bucket,
endpoint: res.endpoint
});
let key = "";
key = res.dir + "/" + files.name;
this.percentageIos = 0;
this.percentageAndroid = 0;
return client.multipartUpload(key, blob, {
progress: (p, checkpoint) => {
if (name === "i_shanghai_map") {
this.percentageIos = Math.floor(p * 100);
} else {
this.percentageAndroid = Math.floor(p * 100);
}
}
});
});
},
}
}
</script>
api/baseInfo.js文件
import request from "@/utils/request";
// 获取oss临时凭证
export function getOssToken(params) {
return request({
url: "/admin/base/getOssToken",
method: "get",
params
});
}
解压:
点击编辑按钮的时候,弹窗出现,开始解压,文件越大,解压过程越久,因此,解压前在弹窗用loading加载
<el-button @click="handleEdit(url)">编辑</el-button>
<script>
export default {
data() {
return {
title: ""
}
},
methods: {
handleEdit(url) {
this.unzipLoading = true;
this.title = "编辑";
this.currentRow = Object.assign({}, row);
this.currentStatus = row.status;
this.currentRow.startTime = formatDate(this.currentRow.startTime);
this.currentRow.endTime = formatDate(this.currentRow.endTime);
this.currentRow.smsAlertTime = formatDate(this.currentRow.smsAlertTime);
this.lookEditDetailDialog = true;
let zipObjIos = await this.unZip(this.currentRow.iOSResource);
let zipObjAndroid = await this.unZip(this.currentRow.androidResource);
this.imageList = [];
console.log("解压", zipObjIos.bgArr);
for (let i = 0; i < zipObjIos.bgArr.length; i++) {
this.imageList.push({
bgImage: zipObjIos.bgArr[i]
});
}
for (let i = 0; i < this.currentRow.diamondCount; i++) {
this.imageList[i].personImage = zipObjIos.gifArr[i];
}
this.currentRow.switchover = zipObjIos.switchover; //展会切换图
this.currentRow.iosUrl = zipObjIos.iosUrl;
this.currentRow.androidUrl = zipObjAndroid.androidUrl;
edit_a_U3d = zipObjAndroid.zipPackage;
edit_i_U3d = zipObjIos.zipPackage;
this.unzipLoading = false;
},
//解压
unZip(iosFile) {
return new Promise(function (resolve, reject) {
let file = iosFile;
axios
.create()
.get(file, {
responseType: "arraybuffer"
})
.then(function (res) {
JSZip.loadAsync(res.data)
.then((content) => {
let bgArr = [];
let gifArr = [];
let androidUrl = "";
let iosUrl = "";
let switchover = "";
let zipObj = {
bgArr: bgArr,
gifArr: gifArr,
androidUrl: androidUrl,
iosUrl: iosUrl,
switchover: switchover,
zipPackage: content
};
let isBg = [];
let isGif = [];
console.log("解压文件", content.files);
for (let name in content.files) {
let nameLength = name.length;
let isImg = name.substring(nameLength - 3, nameLength); //png
let isSwitchover = name.substring(15, 25);
let blob = new Blob([content.files[name]._data.compressedContent]);
if (isImg === "png" && isSwitchover !== "switchover") {
isBg.push(content.files[name]);
} else if (isImg === "gif") {
isGif.push(content.files[name]);
} else if (isImg === "u3d") {
zipObj.androidUrl = URL.createObjectURL(blob);
zipObj.iosUrl = URL.createObjectURL(blob);
} else if (isSwitchover === "switchover") {
zipObj.switchover = URL.createObjectURL(blob);
} else {
}
}
let arr1 = isBg.sort((a, b) => { //背景图替换后排序
let x = a.name.substring(a.name.lastIndexOf("\/") + 1, a.name.length);
let xx = x.substring(0, x.length - 4);
let y = b.name.substring(b.name.lastIndexOf("\/") + 1, b.name.length);
let yy = y.substring(0, y.length - 4);
return xx - yy;
});
arr1.forEach(item => {
let blob = new Blob([item._data.compressedContent]);
zipObj.bgArr.push(URL.createObjectURL(blob));
});
let arr2 = isGif.sort((a, b) => { //人物图替换后排序
let x = a.name.substring(a.name.lastIndexOf("\/") + 1, a.name.length);
let xx = x.substring(0, x.length - 4);
let y = b.name.substring(b.name.lastIndexOf("\/") + 1, b.name.length);
let yy = y.substring(0, y.length - 4);
return xx - yy;
});
arr2.forEach(item => {
let blob = new Blob([item._data.compressedContent]);
zipObj.gifArr.push(URL.createObjectURL(blob));
});
resolve(zipObj);
})
.catch((err) => {
console.log(err);
});
});
});
},
}
}
</script>
完毕
下面说说难点
1、编辑时候,若更换了1张图片再压缩,则压缩包里面只显示这一张新上传的图片,因此需要做一份缓存,更换图片的时候,先删除在添加
2、编辑的时候,改换背景图或者人物图,更换的图片会在数组最后面,因此需要排序后再push