UniApp作为一款跨平台的移动应用开发框架,也提供了相应的接口,方便开发者实现文件的下载与上传功能。本文将介绍如何配置与使用UniApp框架中的文件下载与上传功能。
- 通过 uni.chooseMessageFile 选择本地文件
- 使用 uni.uploadFile 上传文件到服务器
- 实时显示上传进度
- 处理上传成功和失败的情况
- 输入文件 URL 进行下载
- 使用 uni.downloadFile 下载文件
- 实时显示下载进度
- 下载成功后可直接打开文件
- 封装了通用的请求工具
- 提供了文件上传下载的 API
index.vue
<template>
<view class="container">
<view class="section">
<text class="title">文件上传</text>
<button class="select-btn" @click="selectFile">选择文件</button>
<view class="file-info" v-if="selectedFile">
<text class="file-name">{{ selectedFile.name }}</text>
<text class="file-size">{{ selectedFile.size }}</text>
</view>
<button class="upload-btn" @click="uploadSelectedFile" :disabled="!selectedFile">上传文件</button>
<view class="progress-container" v-if="uploading">
<view class="progress-bar" :style="{ width: uploadProgress + '%' }"></view>
<text class="progress-text">{{ uploadProgress }}%</text>
</view>
<view class="result" v-if="uploadResult">
<text class="success-text">上传成功</text>
<text class="file-url">文件地址:{{ uploadResult.url }}</text>
</view>
<view class="error" v-if="uploadError">
<text class="error-text">上传失败:{{ uploadError }}</text>
</view>
</view>
<view class="section">
<text class="title">文件下载</text>
<view class="input-container">
<input
class="url-input"
type="text"
placeholder="请输入文件URL"
v-model="downloadUrl"
/>
<button class="download-btn" @click="startDownload" :disabled="!downloadUrl">下载文件</button>
</view>
<view class="progress-container" v-if="downloading">
<view class="progress-bar" :style="{ width: downloadProgress + '%' }"></view>
<text class="progress-text">{{ downloadProgress }}%</text>
</view>
<view class="result" v-if="downloadSuccess">
<text class="success-text">下载成功</text>
<button class="open-btn" @click="openDownloadedFile">打开文件</button>
</view>
<view class="error" v-if="downloadError">
<text class="error-text">下载失败:{{ downloadError }}</text>
</view>
</view>
</view>
</template>
<script>
import { uploadApi, downloadApi } from './api';
export default {
data() {
return {
selectedFile: null,
uploading: false,
uploadProgress: 0,
uploadResult: null,
uploadError: null,
downloadUrl: '',
downloading: false,
downloadProgress: 0,
downloadSuccess: false,
downloadError: null,
downloadedFilePath: ''
};
},
methods: {
// 选择文件
selectFile() {
uni.chooseMessageFile({
count: 1,
type: 'all',
success: (res) => {
const tempFile = res.tempFiles[0];
this.selectedFile = {
path: tempFile.path,
name: tempFile.name,
size: this.formatSize(tempFile.size)
};
this.uploadError = null;
this.uploadResult = null;
},
fail: (err) => {
this.uploadError = err.errMsg;
}
});
},
// 上传选中的文件
uploadSelectedFile() {
if (!this.selectedFile) return;
this.uploading = true;
this.uploadProgress = 0;
this.uploadError = null;
this.uploadResult = null;
try {
const uploadTask = uploadApi(
this.selectedFile.path,
this.selectedFile.name,
(progress) => {
this.uploadProgress = progress;
}
);
uploadTask.then((res) => {
this.uploading = false;
this.uploadResult = res;
uni.showToast({
title: '上传成功',
icon: 'success'
});
}).catch((err) => {
this.uploading = false;
this.uploadError = err.message;
uni.showToast({
title: '上传失败',
icon: 'none'
});
});
} catch (err) {
this.uploading = false;
this.uploadError = err.message;
uni.showToast({
title: '上传失败',
icon: 'none'
});
}
},
// 开始下载文件
startDownload() {
if (!this.downloadUrl) return;
this.downloading = true;
this.downloadProgress = 0;
this.downloadSuccess = false;
this.downloadError = null;
try {
const downloadTask = downloadApi(
this.downloadUrl,
(progress) => {
this.downloadProgress = progress;
}
);
downloadTask.then((tempFilePath) => {
this.downloading = false;
this.downloadSuccess = true;
this.downloadedFilePath = tempFilePath;
uni.showToast({
title: '下载成功',
icon: 'success'
});
}).catch((err) => {
this.downloading = false;
this.downloadError = err.message;
uni.showToast({
title: '下载失败',
icon: 'none'
});
});
} catch (err) {
this.downloading = false;
this.downloadError = err.message;
uni.showToast({
title: '下载失败',
icon: 'none'
});
}
},
// 打开下载的文件
openDownloadedFile() {
if (!this.downloadedFilePath) return;
uni.openDocument({
filePath: this.downloadedFilePath,
success: () => {
console.log('文件打开成功');
},
fail: (err) => {
uni.showToast({
title: '打开文件失败',
icon: 'none'
});
console.error('打开文件失败:', err);
}
});
},
// 格式化文件大小
formatSize(bytes) {
if (bytes === 0) return '0 B';
const k = 1024;
const sizes = ['B', 'KB', 'MB', 'GB', 'TB'];
const i = Math.floor(Math.log(bytes) / Math.log(k));
return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + ' ' + sizes[i];
}
}
};
</script>
<style>
.container {
padding: 20rpx;
}
.section {
margin-bottom: 40rpx;
background-color: #fff;
border-radius: 10rpx;
padding: 20rpx;
box-shadow: 0 2rpx 10rpx rgba(0, 0, 0, 0.1);
}
.title {
font-size: 36rpx;
font-weight: bold;
margin-bottom: 20rpx;
color: #333;
display: block;
}
.select-btn, .upload-btn, .download-btn, .open-btn {
width: 100%;
height: 80rpx;
line-height: 80rpx;
text-align: center;
background-color: #007AFF;
color: #fff;
border-radius: 8rpx;
margin-bottom: 20rpx;
font-size: 28rpx;
}
.select-btn[disabled], .upload-btn[disabled], .download-btn[disabled] {
background-color: #CCCCCC;
}
.file-info {
display: flex;
justify-content: space-between;
margin-bottom: 20rpx;
font-size: 28rpx;
color: #666;
}
.progress-container {
width: 100%;
height: 20rpx;
background-color: #f3f3f3;
border-radius: 10rpx;
margin-bottom: 20rpx;
position: relative;
}
.progress-bar {
height: 100%;
background-color: #007AFF;
border-radius: 10rpx;
transition: width 0.3s ease;
}
.progress-text {
position: absolute;
right: 0;
top: -30rpx;
font-size: 24rpx;
color: #666;
}
.result, .error {
margin-bottom: 20rpx;
}
.success-text {
color: #4CD964;
font-size: 28rpx;
display: block;
margin-bottom: 10rpx;
}
.error-text {
color: #FF3B30;
font-size: 28rpx;
display: block;
margin-bottom: 10rpx;
}
.file-url {
color: #007AFF;
font-size: 24rpx;
word-break: break-all;
display: block;
}
.input-container {
margin-bottom: 20rpx;
}
.url-input {
width: 100%;
height: 80rpx;
line-height: 80rpx;
border: 1rpx solid #ddd;
border-radius: 8rpx;
padding: 0 20rpx;
margin-bottom: 20rpx;
font-size: 28rpx;
box-sizing: border-box;
}
</style>
api.js
// pages/upload-download/api.js
import { uploadFile, downloadFile, getUploadProgress, getDownloadProgress } from '@/utils/request';
// 文件上传API
export function uploadApi(filePath, fileName, onProgress) {
const uploadTask = uploadFile('/upload', filePath, fileName);
// 如果有进度回调,监听进度
if (typeof onProgress === 'function') {
getUploadProgress(uploadTask, onProgress);
}
return uploadTask;
}
// 文件下载API
export function downloadApi(fileUrl, onProgress) {
const downloadTask = downloadFile(fileUrl);
// 如果有进度回调,监听进度
if (typeof onProgress === 'function') {
getDownloadProgress(downloadTask, onProgress);
}
return downloadTask;
}
request.js
// utils/request.js
import uni from '@dcloudio/uni-app';
/**
* 上传文件
* @param {string} url 上传地址
* @param {string} filePath 文件路径
* @param {string} name 文件字段名
* @param {object} [data] 额外数据
* @returns {Promise} 上传任务
*/
export function uploadFile(url, filePath, name, data = {}) {
return uni.uploadFile({
url: url,
filePath: filePath,
name: name,
formData: data,
success: (res) => {
if (res.statusCode === 200) {
return JSON.parse(res.data);
} else {
throw new Error(`上传失败,状态码:${res.statusCode}`);
}
},
fail: (err) => {
throw new Error(`上传失败:${err.errMsg}`);
}
});
}
/**
* 下载文件
* @param {string} url 文件地址
* @returns {Promise} 下载任务
*/
export function downloadFile(url) {
return uni.downloadFile({
url: url,
success: (res) => {
if (res.statusCode === 200) {
return res.tempFilePath;
} else {
throw new Error(`下载失败,状态码:${res.statusCode}`);
}
},
fail: (err) => {
throw new Error(`下载失败:${err.errMsg}`);
}
});
}
/**
* 获取上传进度
* @param {object} uploadTask 上传任务
* @param {function} callback 进度回调
*/
export function getUploadProgress(uploadTask, callback) {
uploadTask.onProgressUpdate((res) => {
callback(res.progress);
});
}
/**
* 获取下载进度
* @param {object} downloadTask 下载任务
* @param {function} callback 进度回调
*/
export function getDownloadProgress(downloadTask, callback) {
downloadTask.onProgressUpdate((res) => {
callback(res.progress);
});
}
注意: