说明
做项目使用的layui搭建的后台
后端返回的数据结构
前端依赖插件
- Jszip https://cdn.bootcdn.net/ajax/libs/jszip/3.5.0/jszip.js
- FileSaver https://cdn.bootcdn.net/ajax/libs/FileSaver.js/2.0.2/FileSaver.js
注意, layui引入第三方组件 需要将第三方组件包裹
引入JSzip
layui.define(function(exports){
// ↓这里粘贴jszip的代码
// ↑
exports('jszip', new JSZip());
});
引入FileSaver
layui.define(function(exports){
// ↓这里粘贴FileSaver的代码
// ↑
exports('filesaver', saveAs);
});
页面加载第三方代码
layui.extend({
jszip:'/static/js/jszip',
filesaver:'/static/js/filesaver',
})
layui.use(['form', 'layer', 'jquery', 'layedit', 'upload','table','jszip','filesaver'],function(){
var jszip = layui.jszip;
var saveAs = layui.filesaver;
})
页面加入点击事件
<button class="layui-btn clockClick" >
下载打卡信息
</button>
***
$(".clockClick").on("click",function(res){
var data = layui.table.checkStatus("dataTable").data; // 获取复选框选择的所有数据
console.log(data)
if(data.length == 0){
layer.msg("请选择信息");
return false;
}
})
展示效果
主要代码部分
点击事件
$(".clockClick").on("click",function(res){
var data = layui.table.checkStatus("dataTable").data;
if(data.length == 0){
layer.msg("请选择信息");
return false;
}
jszip.remove("打卡记录"); // 清理掉之前文件
var index = layer.load(0, {shade: true}); //loading加载
var img = jszip.folder("打卡记录"); // 生成图片文件夹
var pro = data.map(async (res,k)=>{
return new Promise(async (resolve, reject) =>{
var name = img.folder(res.student_name);
console.log(res, 'name')
var retImg,retVid = false;
if(res.image.length == 0){
console.log("空图片")
retImg =true;
}
if(res.video.length == 0){
console.log("空视频")
retVid = true;
}
res.image.map(async (imgItem,imgKey)=>{
var hui = await downImg(res, imgItem,name);
console.log("下载图片",res.id , imgKey, (res.image.length - 1) )
if(imgKey === (res.image.length - 1) ){
console.log("成功")
retImg = true;
}
if(retImg && retVid){
resolve(true)
}
})
res.video.map(async (videoItem,videoKey)=>{
var hui =await downVideo(res, videoItem, name);
console.log("下载视频",res.id)
if((res.video.length -1) === videoKey){
retVid = true;
}
if(retImg && retVid){
resolve(true)
}
})
if(retImg && retVid){
resolve(true)
}
})
});
console.log(pro); // 此处打印用来查看控制台是否全部完成
Promise.all(
pro
).then(() =>{
layer.closeAll('loading'); //关闭加载层
saveFile(); // 全部执行完 保存代码
console.log('结束')
}).catch((e) => {
layer.closeAll('loading'); //关闭加载层
layer.msg("下载失败");
console.error('结束',e)
})
return false;
})
下载图片代码
function downImg(res, imgItem, name){
return new Promise(async (resolve, reject) =>{
const image = new Image()
image.setAttribute('crossOrigin', 'Anonymous') // 设置 crossOrigin 属性,解决图片跨域报错
//设置图片地址----稍后进行base64转换
image.src = imgItem
image.onload = () => {
const canvas = document.createElement('canvas')
// 让画布的宽高等于图片的宽高
canvas.width = image.width
canvas.height = image.height
// 然后在画布上进行画画
const ctx = canvas.getContext('2d')
// 开始画图片,1.绘制的对象2.绘制的位置,3绘制的宽高
ctx.drawImage(image, 0, 0, image.width, image.height)
const url = canvas.toDataURL();
var img_arr = url.split(','); //分割开数据
name.file(res.tent+".png", img_arr[1], {base64:true});//图片批量写入文件
resolve(res.id)
}
})
}
下载视频代码
function downVideo(res, videoItem, name){
return new Promise(async (resolve, reject) =>{
videoItem = videoItem.replace(/http[^s]/i,"https:");
await xhrequest(videoItem).then((vres) => {
name.file( res.tent+'.mp4', vres, { Blob: true,})
resolve(res.id)
})
})
}
async function xhrequest(url) {
let data = await fetch(url, { mode: 'cors' })
.then((response) => response.blob())
.then((res) => {
return res
})
return data
}
保存文件代码
function saveFile(){
jszip.generateAsync({
type:"blob", //压缩类型
compression:"DEFLATE", //store:默认不压缩,defalte:需要压缩
compressionOptions:{
level:9 //压缩等级1--9, 1:压缩速度最快,9:最优压缩方式
}
}).then(function(content) {
layer.closeAll('loading'); //关闭加载层
// see FileSaver.js
saveAs(content, "文件名.zip");
});
}
感悟
其实最主要的用到的就是Promise
来监听代码, Promise
运行后 一直保持加载中的状态, 只有代码运行到resolve
部分才会返回成功, 或者运行到reject
返回失败.
因为要下载多个视频和图片, 所以用Promise.all
来监听多个
主要代码里面的retImg , retVid
用来一次次的遍历 每条数据内的视频数组和图片数组遍历完毕, 如果都完毕了 才会返回成功
当所有被选择的数据都返回成功后, 才会走到Promise.all
的then
内
参考
各种视频,图片转换参考自
https://blog.csdn.net/WoNiuDeXiaYiYe/article/details/127051493