概览
uniapp实现多文件下载,保存到本地,因为使用的是uni.downloadFile 实现文件的下载,每次只能下载一个,需要下载多个文件,并保存到本地,并把保存的地址存储到对应的数据组中,并实现进度条显示。
需求分析
1、文件下载并保存到本地 直接使用uni.downloadFile 和uni.saveFile 两个方法既可以实现。
2、如有多个文件下载,需要异步一个一个去下载,并把保存到本地的路径赋值给传过来的数据。
3、如果使用for循环,会存存储数据混乱的情况,或者说直接保存的路径只保存到了最后一个数组对象中,无法实现保存对应的存储路径到数组。
4、进度条显示,根据下载的方法,进行监听进度返回到页面进行显示进度条的变化。
具体实现
download.js 代码
// +----------------------------------------------------------------------
// | 下载工具类
// +----------------------------------------------------------------------
import {
HTTP_REQUEST_URL
} from '@/config/app';
export const hostUrlUpLoad = HTTP_REQUEST_URL + '/upload/';
export const hostUrl = HTTP_REQUEST_URL;
import {
getStudyData,
getTestData
} from '@/api/api.js';
/**
* 下载分类相关数据
* 图片加载到本地
* @returns boolean
*/
export async function downloadClass(data, inta) {
if (data.length > 0 && inta < data.length) {
try {
const downloadTask = await uni.downloadFile({
url: data[inta].icon_path.includes('upload') ? hostUrl + data[inta].icon_path :
hostUrlUpLoad + data[inta].icon_path,
success: res => {
if (res.statusCode === 200) {
uni.saveFile({
tempFilePath: res.tempFilePath, // 下载文件的临时路径
success: saveRes => {
data[inta].icon_path = saveRes.savedFilePath
if (inta < data.length - 1) {
inta = inta + 1
downloadClass(data, inta)
} else {
uni.setStorageSync('classData', data)
}
},
fail: err => {
if (inta < data.length - 1) {
inta = inta + 1
downloadClass(data, inta)
} else {
uni.setStorageSync('classData', data)
}
}
});
} else {
if (inta < data.length - 1) {
inta = inta + 1
downloadClass(data, inta)
} else {
uni.setStorageSync('classData', data)
}
}
},
fail: err => {
if (inta < data.length - 1) {
inta = inta + 1
downloadClass(data, inta)
} else {
uni.setStorageSync('classData', data)
}
}
});
downloadTask.onProgressUpdate(resda => {})
} catch (e) {
if (inta < data.length - 1) {
inta = inta + 1
downloadClass(data, inta)
} else {
uni.setStorageSync('classData', data)
}
//TODO handle the exception
}
}
}
/**
* 下载科目数据
* 图片加载到本地
* @returns boolean
*/
export async function downloadSubject(data, inta, callBack) {
var callBackFun = callBack;
if (data.length > 0 && inta < data.length) {
try {
const downloadTask = await uni.downloadFile({
url: data[inta].icon_path.includes('upload') ? hostUrl + data[inta].icon_path :
hostUrlUpLoad + data[inta].icon_path,
success: res => {
if (res.statusCode === 200) {
uni.saveFile({
tempFilePath: res.tempFilePath, // 下载文件的临时路径
success: saveRes => {
data[inta].icon_path = saveRes.savedFilePath
if (inta < data.length - 1) {
inta = inta + 1
downloadSubject(data, inta, callBackFun)
} else {
uni.setStorageSync('SubjectData', data, callBackFun)
requestSubjectClass(data, 0, callBackFun)
}
},
fail: err => {
if (inta < data.length - 1) {
inta = inta + 1
downloadSubject(data, inta, callBackFun)
} else {
uni.setStorageSync('SubjectData', data)
requestSubjectClass(data, 0, callBackFun)
}
}
});
} else {
if (inta < data.length - 1) {
inta = inta + 1
downloadSubject(data, inta, callBackFun)
} else {
uni.setStorageSync('SubjectData', data)
requestSubjectClass(data, 0, callBackFun)
}
}
},
fail: err => {
if (inta < data.length - 1) {
inta = inta + 1
downloadSubject(data, inta, callBackFun)
} else {
uni.setStorageSync('SubjectData', data)
requestSubjectClass(data, 0, callBackFun)
}
}
});
downloadTask.onProgressUpdate(resda => {
callBackFun(resda.progress, false)
})
} catch (e) {
//TODO handle the exception
if (inta < data.length - 1) {
inta = inta + 1
downloadSubject(data, inta, callBackFun)
} else {
uni.setStorageSync('SubjectData', data)
requestSubjectClass(data, 0, callBackFun)
}
}
}
}
/**
* 根据科目列表赋值分类数据
* @param {Object} data
* @param {Object} inta
*/
export async function requestSubjectClass(data, inta, callBack) {
const callBackFun = callBack;
if (data.length > 0 && inta < data.length) {
try {
await getStudyData(data[inta].id).then(res => {
if (res.data.code == 200 && res.data.status == 'success' && res.data.data.count > 0) {
data[inta].categoryData = res.data.data.list
if (inta < data.length - 1) {
inta = inta + 1
requestSubjectClass(data, inta, callBackFun)
} else {
uni.setStorageSync('SubjectData', data)
downloadSubjectFile(data, 0, 0, callBackFun)
}
} else {
if (inta < data.length - 1) {
inta = inta + 1
requestSubjectClass(data, inta, callBackFun)
} else {
uni.setStorageSync('SubjectData', data)
downloadSubjectFile(data, 0, 0, callBackFun)
}
}
})
} catch (e) {
//TODO handle the exception
if (inta < data.length - 1) {
inta = inta + 1
requestSubjectClass(data, inta, callBackFun)
} else {
uni.setStorageSync('SubjectData', data)
downloadSubjectFile(data, 0, 0, callBackFun)
}
}
}
}
/**
* 下载文件到本地
* @returns boolean
*/
export async function downloadSubjectFile(data, inta, intaClass, callBack) {
const callBackFun = callBack;
if (data.length > 0 && inta < data.length) {
if (data[inta].categoryData.length > 0 && intaClass < data[inta].categoryData.length) {
try {
var filePath = ''
if (data[inta].categoryData[intaClass].file_path.includes('upload')) {
if (data[inta].categoryData[intaClass].file_path.charAt(0) == '/') {
filePath = hostUrl + data[inta].categoryData[intaClass].file_path
} else {
filePath = "http://" + data[inta].categoryData[intaClass].file_path
}
} else {
filePath = hostUrlUpLoad + data[inta].categoryData[intaClass].file_path
}
const downloadTask = await uni.downloadFile({
url: filePath,
success: res => {
if (res.statusCode === 200) {
uni.saveFile({
tempFilePath: res.tempFilePath, // 下载文件的临时路径
success: saveRes => {
data[inta].categoryData[intaClass].file_path = saveRes.savedFilePath
if (intaClass < data[inta].categoryData.length - 1) {
intaClass = intaClass + 1
downloadSubjectFile(data, inta, intaClass,callBackFun)
} else {
if (inta < data.length - 1) {
inta = inta + 1
downloadSubjectFile(data, inta, 0, callBackFun)
} else {
uni.setStorageSync('SubjectData', data)
callBackFun(100, true)
}
}
},
fail: err => {
console.log("保存文件失败 ")
if (intaClass < data[inta].categoryData.length - 1) {
intaClass = intaClass + 1
downloadSubjectFile(data, inta, intaClass,
callBackFun)
} else {
if (inta < data.length - 1) {
inta = inta + 1
downloadSubjectFile(data, inta, 0, callBackFun)
} else {
uni.setStorageSync('SubjectData', data)
callBackFun(100, true)
}
}
}
});
} else {
if (intaClass < data[inta].categoryData.length - 1) {
intaClass = intaClass + 1
downloadSubjectFile(data, inta, intaClass, callBackFun)
} else {
if (inta < data.length - 1) {
inta = inta + 1
downloadSubjectFile(data, inta, 0, callBackFun)
} else {
uni.setStorageSync('SubjectData', data)
callBackFun(100, true)
}
}
}
},
fail: err => {
console.log("下载失败 fail ")
if (intaClass < data[inta].categoryData.length - 1) {
intaClass = intaClass + 1
downloadSubjectFile(data, inta, intaClass, callBackFun)
} else {
if (inta < data.length - 1) {
inta = inta + 1
downloadSubjectFile(data, inta, 0, callBackFun)
} else {
uni.setStorageSync('SubjectData', data)
callBackFun(100, true)
}
}
}
});
downloadTask.onProgressUpdate(resda => {
callBackFun(resda.progress, false)
})
} catch (e) {
//TODO handle the exception
console.log("downloadSubjectFile catch " + JSON.stringify(e))
if (intaClass < data[inta].categoryData.length - 1) {
intaClass = intaClass + 1
downloadSubjectFile(data, inta, intaClass, callBackFun)
} else {
if (inta < data.length - 1) {
inta = inta + 1
downloadSubjectFile(data, inta, 0, callBackFun)
} else {
console.log("打印保存的科目数据 downloadSubjectFile " + JSON.stringify(data))
uni.setStorageSync('SubjectData', data)
callBackFun(100, true)
}
}
}
} else {
if (intaClass < data[inta].categoryData.length - 1) {
intaClass = intaClass + 1
downloadSubjectFile(data, inta, intaClass, callBackFun)
} else {
if (inta < data.length - 1) {
inta = inta + 1
downloadSubjectFile(data, inta, 0, callBackFun)
} else {
console.log("打印保存的科目数据 downloadSubjectFile " + JSON.stringify(data))
uni.setStorageSync('SubjectData', data)
callBackFun(100, true)
}
}
}
}
}
/**
* 根据科目列表获取题库
* @param {Object} subjectData
*/
export async function requestSubjectTestData(subjectData) {
try {
await getTestData(subjectData.id).then(res => {
if (res.data.code == 200 && res.data.status == 'success') {
uni.removeStorageSync('CNLLIST' + subjectData.id)
uni.removeStorageSync('CNLLISTCOUNT' + subjectData.id)
uni.removeStorageSync('ENLLIST' + subjectData.id)
uni.removeStorageSync('ENLLISTCOUNT' + subjectData.id)
uni.setStorageSync('CNLLIST' + subjectData.id, res.data.data.list)
uni.setStorageSync('CNLLISTCOUNT' + subjectData.id, res.data.data.count)
uni.setStorageSync('ENLLIST' + subjectData.id, res.data.data.english_list)
uni.setStorageSync('ENLLISTCOUNT' + subjectData.id, res.data.data.english_count)
} else {
uni.removeStorageSync('CNLLIST' + subjectData.id)
uni.removeStorageSync('CNLLISTCOUNT' + subjectData.id)
uni.removeStorageSync('ENLLIST' + subjectData.id)
uni.removeStorageSync('ENLLISTCOUNT' + subjectData.id)
}
})
} catch (e) {
console.log('报错信息 ' + JSON.stringify(subjectData.id))
//TODO handle the exception
}
}
/**
* 根据科目列表赋值分类数据
* @param {Object} data
* @param {Object} inta
*/
export async function requestSubjectClassSize(data, inta, callBack) {
if (data.length > 0 && inta < data.length) {
try {
await getStudyData(data[inta].id).then(res => {
if (res.data.code == 200 && res.data.status == 'success' && res.data.data.count > 0) {
data[inta].categoryData = res.data.data.list
if (inta < data.length - 1) {
inta = inta + 1
requestSubjectClassSize(data, inta, callBack)
} else {
requestDownloadFileSize(data, 0, 0,0, callBack)
}
} else {
if (inta < data.length - 1) {
inta = inta + 1
requestSubjectClassSize(data, inta, callBack)
} else {
requestDownloadFileSize(data, 0, 0,0, callBack)
}
}
})
} catch (e) {
//TODO handle the exception
if (inta < data.length - 1) {
inta = inta + 1
requestSubjectClassSize(data, inta, callBack)
} else {
requestDownloadFileSize(data, 0, 0,0, callBack)
}
}
}
}
/**
* 下载文件总大小
* @returns boolean
*/
export async function requestDownloadFileSize(data, inta, intaClass, contentLength, callBack) {
if (data.length > 0 && inta < data.length) {
if (data[inta].categoryData.length > 0 && intaClass < data[inta].categoryData.length) {
try {
var filePath = ''
if (data[inta].categoryData[intaClass].file_path.includes('upload')) {
if (data[inta].categoryData[intaClass].file_path.charAt(0) == '/') {
filePath = hostUrl + data[inta].categoryData[intaClass].file_path
} else {
filePath = "http://" + data[inta].categoryData[intaClass].file_path
}
} else {
filePath = hostUrlUpLoad + data[inta].categoryData[intaClass].file_path
}
await uni.request({
url: filePath,
method: 'head',
// responseType: 'arraybuffer', // 或者其他如'text'、'blob'等,取决于你需要的内容类型
// header: {
// 'Accept-Encoding': 'gzip, deflate'
// },
success(res) {
if (res.statusCode === 200) {
if (intaClass < data[inta].categoryData.length - 1) {
intaClass = intaClass + 1
if(res.header['Content-Length'] || res.header['content-length']){
console.log("filePath " + filePath + ' ' + JSON.stringify(res.header['Content-Length']))
contentLength = contentLength + parseInt(res.header['Content-Length']?res.header['Content-Length']:res.header['content-length'],10); // 获取Content-Length字段的值
}
requestDownloadFileSize(data, inta, intaClass,contentLength,callBack)
} else {
if (inta < data.length - 1) {
inta = inta + 1
if(res.header['Content-Length'] || res.header['content-length']){
contentLength = contentLength + parseInt(res.header['Content-Length']?res.header['Content-Length']:res.header['content-length'],10); // 获取Content-Length字段的值
}
requestDownloadFileSize(data, inta, 0,contentLength, callBack)
} else {
callBack(contentLength)
}
}
} else {
if (intaClass < data[inta].categoryData.length - 1) {
intaClass = intaClass + 1
requestDownloadFileSize(data, inta, intaClass,contentLength, callBack)
} else {
if (inta < data.length - 1) {
inta = inta + 1
requestDownloadFileSize(data, inta, 0,contentLength, callBack)
} else {
callBack(contentLength)
}
}
}
},
error(err) {
console.error('请求错误:', err);
if (intaClass < data[inta].categoryData.length - 1) {
intaClass = intaClass + 1
requestDownloadFileSize(data, inta, intaClass,contentLength, callBack)
} else {
if (inta < data.length - 1) {
inta = inta + 1
requestDownloadFileSize(data, inta, 0,contentLength, callBack)
} else {
callBack(contentLength)
}
}
},
networkTimeout: 5000, // 设置超时时间
timeout: 5000 // 设置整体请求超时时间
})
} catch (e) {
//TODO handle the exception
console.log("requestDownloadFileSize catch " + JSON.stringify(e))
if (intaClass < data[inta].categoryData.length - 1) {
intaClass = intaClass + 1
requestDownloadFileSize(data, inta, intaClass,contentLength, callBack)
} else {
if (inta < data.length - 1) {
inta = inta + 1
requestDownloadFileSize(data, inta, 0,contentLength, callBack)
} else {
callBack(contentLength)
}
}
}
} else {
if (intaClass < data[inta].categoryData.length - 1) {
intaClass = intaClass + 1
requestDownloadFileSize(data, inta, intaClass,contentLength, callBack)
} else {
if (inta < data.length - 1) {
inta = inta + 1
requestDownloadFileSize(data, inta, 0,contentLength, callBack)
} else {
callBack(contentLength)
}
}
}
}
}
/**
* @param {Object} data
* @param {Object} inta
* @param {Object} contentLength
* @param {Object} callBack
*/
export async function requestFileSize(data, inta, contentLength, callBack) {
if (data.length > 0 && inta < data.length) {
try {
uni.request({
url: downloadUrl,
method: 'GET',
responseType: 'arraybuffer', // 或者其他如'text'、'blob'等,取决于你需要的内容类型
header: {
'Accept-Encoding': 'gzip, deflate'
},
success(res) {
if (res.statusCode === 200 && res.data) {
if (inta < data.length - 1) {
inta = inta + 1
if(res.header['Content-Length'] || res.header['content-length']){
contentLength = contentLength + parseInt(res.header['Content-Length']?res.header['Content-Length']:res.header['content-length'],10); // 获取Content-Length字段的值
}
console.log(contentLength + ' 字节');
requestFileSize(data, inta, contentLength, callBack)
} else {
callBack(contentLength)
}
} else {
if (inta < data.length - 1) {
inta = inta + 1
requestFileSize(data, inta, contentLength, callBack)
} else {
callBack(contentLength)
}
}
},
error(err) {
console.error('请求错误:', err);
if (inta < data.length - 1) {
inta = inta + 1
requestFileSize(data, inta, contentLength, callBack)
} else {
callBack(contentLength)
}
},
networkTimeout: 5000, // 设置超时时间
timeout: 5000 // 设置整体请求超时时间
});
} catch (e) {
//TODO handle the exception
if (inta < data.length - 1) {
inta = inta + 1
requestFileSize(data, inta, contentLength, callBack)
} else {
callBack(contentLength)
}
}
}
}
export default {
downloadClass,
downloadSubject,
requestSubjectTestData,
requestDownloadFileSize,
requestSubjectClassSize
};
实现的逻辑是,下载完成一个文件,然后把保存到本地的路径存储到传过来对应的数据中,把原来线上的文件地址替换为本地路径,然后在进行下一个。
进度条显示
<template>
<view style="width: 100%;height: 100%;display: flex;align-items: center;justify-content: center;position: relative;">
<view style="position: absolute;top: 80rpx;display: flex;flex-direction: column;align-items: center;justify-content: center;">
<image src="../../static/kaoshilogo.png" style="width: 80rpx;" mode="widthFix"></image>
<view style="margin-top: 20rpx;font-family: Source Han Sans-Bold;font-size: 18rpx;">{{language.AppName}}</view>
</view>
<view style="position: absolute;bottom: 30rpx;width: 100%;display: flex;align-items: center;justify-content: center;flex-direction: column;">
<view style="width: 60%;font-size: 8rpx;text-align: center;margin-bottom: 3rpx;">{{language.zhengzaigengxinziliao}}</view>
<view class="progress-bar">
<view class="progress-bar__fill" :style="{width: progress}"></view>
</view>
</view>
</view>
</template>
<script>
import {
getSubjectData,
getClassData,
getList,
uploadStudyTime,
uploadTestData,
uploadOpen
} from '@/api/api.js'
export default {
data() {
return {
fileManager: null,
openData: [],
progress: '',
language: getApp().globalData.language,
}
},
onLoad() {
this.uploadOpen()
//获取总分类数据
if (!uni.getStorageSync("classData")) {
this.getClassDataPage()
}
//获取科目数据
if (!uni.getStorageSync("SubjectData")) {
this.getSubjectDataPage()
}else{
if(uni.getStorageSync('userInfo')){
uni.switchTab({
url: '/pages/home/home'
})
}else{
uni.navigateTo({
url: '/pages/login/login'
})
}
}
if(uni.getStorageSync('userInfo') && uni.getStorageSync('userInfo').userName != 'Guest'){
if(uni.getStorageSync('uploadTime')){
this.uploadSyudyTime()
}
if(uni.getStorageSync('uploadTestTime')){
this.uploadTestTime()
}
}
},
methods: {
async getClassDataPage(){
var that = this
await getClassData().then(res => {
if (res.data.code == 200 && res.data.status == 'success') {
that.$download.downloadClass(res.data.data.list, 0)
} else if (res.statusCode == '404' || res.status == 1) {
console.log("网路请求失败")
} else {
console.log(res)
}
})
},
async getSubjectDataPage(){
var that = this
await getSubjectData().then(res => {
if (res.data.code == 200 && res.data.status == 'success') {
if(res.data && res.data.data && res.data.data.list && res.data.data.list.length > 0){
for (var i = 0; i < res.data.data.list.length; i++) {
this.$download.requestSubjectTestData(res.data.data.list[i]);
}
this.$download.downloadSubject(res.data.data.list, 0,function(progress,boobleTo){
that.progress = progress + "%"
if(boobleTo){
getApp().globalData.version = '1.0.' + that.$utils.formatDateTime()
if(uni.getStorageSync('userInfo')){
uni.switchTab({
url: '/pages/home/home'
})
}else{
uni.navigateTo({
url: '/pages/login/login'
})
}
}
});
}else{
if(uni.getStorageSync('userInfo')){
uni.switchTab({
url: '/pages/home/home'
})
}else{
uni.navigateTo({
url: '/pages/login/login'
})
}
}
} else if (res.statusCode == '404' || res.status == 1) {
console.log("网路请求失败")
uni.showToast({
title: that.language.startToastnetworkMsg,
icon: 'none',
duration: 1500
})
if(uni.getStorageSync('userInfo')){
uni.switchTab({
url: '/pages/home/home'
})
}else{
uni.navigateTo({
url: '/pages/login/login'
})
}
} else {
uni.showToast({
title: that.language.startToastnetworkMsg,
icon: 'none',
duration: 1500
})
if(uni.getStorageSync('userInfo')){
uni.switchTab({
url: '/pages/home/home'
})
}else{
uni.navigateTo({
url: '/pages/login/login'
})
}
}
})
},
async uploadSyudyTime(){
await uploadStudyTime({"data": uni.getStorageSync('uploadTime')}).then(res=>{
if(res.data.code == 200 && res.data.status == 'success'){
uni.removeStorageSync('uploadTime')
}
})
},
async uploadTestTime(){
await uploadTestData({"data": uni.getStorageSync('uploadTestTime')}).then(res=>{
if(res.data.code == 200 && res.data.status == 'success'){
uni.removeStorageSync('uploadTestTime')
}
})
},
async uploadOpen(){
this.openData = [];
if(uni.getStorageSync('uploadOpen')){
this.openData = uni.getStorageSync('uploadOpen')
this.openData.push({"date": this.$utils.formatDateTime()})
}else{
this.openData[0] = {"date": this.$utils.formatDateTime()}
}
await uploadOpen({"data": this.openData}).then(res=>{
if(res.data.code == 200 && res.data.status == 'success'){
uni.removeStorageSync('uploadOpen')
}else{
uni.setStorageSync('uploadOpen',this.openData)
}
})
}
}
}
</script>
<style>
page{
width: 100%;
height: 100vh;
}
.progress-bar {
background-color: #cccccc; /* 进度条背景颜色 */
height: 10rpx;
width: 60%;
border-radius: 5rpx;
}
.progress-bar__fill {
height: 100%;
background-color: green; /* 完成部分的颜色 */
transition: width 0.1s ease-in-out; /* 平滑过渡效果 */
border-radius: 5rpx;
}
</style>
有部分不需要的代码,可以自己删除掉即可。