在移动应用开发中,文件的上传和下载是常见的功能需求。本文将详细介绍一个基于Uniapp的文件上传下载工具的实现,帮助开发者快速集成文件操作功能到自己的应用中。
文件上传功能通过uploadFile
函数实现,它接收一个文件URL作为参数,返回一个Promise对象,便于异步处理上传结果。
javascript/**
* 上传文件到服务器
* @param {string} url - 要上传的本地文件路径
* @returns {Promise} 返回一个Promise对象,成功时解析为文件URL,失败时拒绝并返回错误
*/
export const uploadFile = (url) => {
return new Promise((resolve, reject) => {
// 使用uni.uploadFile API上传文件
uni.uploadFile({
url: baseUrl + '/file/upload', // 拼接基础URL和上传接口路径
filePath: url, // 要上传的文件路径
name: 'file', // 后端接收的文件字段名
header: {
'medical-trial-drug': uni.getStorageSync('token') // 添加认证token到请求头
},
success: (response) => {
// 上传成功回调
const res = JSON.parse(response.data) // 解析响应数据
if (res.code === 200) {
resolve(res.data.url) // 上传成功,解析返回的文件URL
} else {
uni.$u.toast('上传失败') // 显示上传失败提示
reject(new Error('上传失败')) // 拒绝Promise
}
},
fail: (err) => {
// 上传失败回调
reject(err) // 拒绝Promise并传递错误对象
}
})
})
}
文件下载功能通过downloadFile
函数实现,它能够根据文件类型自动选择适当的打开方式,并提供了下载进度显示。
javascript/**
* 下载并打开文件,根据文件类型自动选择打开方式
* @param {string} url - 要下载的文件远程URL
*/
export const downloadFile = (url) => {
console.log('文件原始远程地址:', url)
const suffix = getFileExtension(url) // 获取文件后缀名
console.log('文件后缀为:', suffix)
// 定义文档类型后缀数组
const docSuffix = ['doc', 'xls', 'ppt', 'pdf', 'docx', 'xlsx', 'pptx']
// 定义图片类型后缀数组
const imgSuffix = ['jpg','jpeg','png','bmp','webp','tiff','tif','gif','svg','ai','raw','heic','heif','ico','eps','avif','jxr','hdp','xcf','psd','psb','drf','dng','xpm','pnm','ppm','pgm','pbm']
const fs = uni.getFileSystemManager() // 获取文件系统管理器实例
removeTempFile(fs) // 清理临时文件
// 创建下载任务
const downloadTask = uni.downloadFile({
url: url, // 文件的下载路径
success: (res) => {
// 下载成功回调
const fileName = res.tempFilePath.split('/').pop().split('#')[0].split('?')[0]
const localFilePath = `${uni.env.USER_DATA_PATH}/${fileName}`
console.log('文件路径:', localFilePath)
// 根据文件类型选择打开方式
if (docSuffix.includes(suffix)) {
// 文档类型使用openDocument打开
uni.openDocument({
filePath: res.tempFilePath,
showMenu: true, // 显示菜单,允许用户选择其他应用打开
success: (res) => {
console.log('打开文档成功')
}
})
} else if (imgSuffix.includes(suffix)) {
// 图片类型使用previewImage预览
uni.previewImage({
urls: [res.tempFilePath],
showMenu: true, // 显示菜单,允许用户保存图片
success: (res) => {
console.log('打开图片成功')
}
})
} else {
// 其他类型提示不支持并尝试保存到本地
uni.$u.toast('图片不支持打开')
fs.saveFile({
tempFilePath: res.tempFilePath, // 临时文件路径
filePath: localFilePath, // 要保存的本地路径
success: (res) => {
uni.$u.toast('图片已保存到本地:', localFilePath)
},
fail: (err) =>{
console.log('保存失败', err)
},
complete: () => {
console.log('保存完成')
}
})
}
},
fail: (err) =>{
console.log('下载失败', err)
},
complete:() => {
console.log('下载完成')
}
})
// 监听下载进度变化
downloadTask.onProgressUpdate((res) => {
console.log('下载进度:', res.progress)
// 显示下载进度提示
uni.showLoading({
title: `下载中 ${res.progress}%`,
mask: true // 添加遮罩防止用户操作
})
if (res.progress === 100) {
uni.hideLoading() // 下载完成隐藏提示
}
})
}
javascript/**
* 清理缓存中的临时文件
* @param {Object} fs - 文件系统管理器实例
*/
const removeTempFile = (fs) => {
// 获取所有已保存的文件列表
fs.getSavedFileList({
success: (res) => {
console.log('缓存中的文件为:', res.fileList)
if (res.fileList.length > 0) {
// 遍历并删除所有临时文件
for (let i = 0; i < res.fileList.length; i++) {
fs.removeSavedFile({
filePath: res.fileList[i].filePath, // 要删除的文件路径
success: (res) => {
console.log('删除成功', res)
},
fail: (err) =>{
console.log('删除失败', err)
},
complete: (res) => {
console.log('删除文件完成', res)
}
})
}
}
},
error: (res) => {
console.log('获取文件异常', res)
},
complete: (res) => {
console.log('获取文件完成')
}
})
}
javascript/**
* 从URL中提取文件扩展名
* @param {string} url - 文件URL
* @returns {string} 文件扩展名(小写)
*/
function getFileExtension(url) {
// 使用正则匹配URL中的文件扩展名
return (url.match(/\.([^./]+)(?:[\?#]|$)/)?.[1] || '').toLowerCase()
}
javascript// 上传文件
import { baseUrl } from '@/util/http'
/**
* 上传文件到服务器
* @param {string} url - 要上传的本地文件路径
* @returns {Promise} 返回一个Promise对象,成功时解析为文件URL,失败时拒绝并返回错误
*/
export const uploadFile = (url) => {
return new Promise((resolve, reject) => {
uni.uploadFile({
url: baseUrl + '/file/upload',
filePath: url,
name: 'file',
header: {
'medical-trial-drug': uni.getStorageSync('token')
},
success: (response) => {
const res = JSON.parse(response.data)
if (res.code === 200) {
resolve(res.data.url)
} else {
uni.$u.toast('上传失败')
reject(new Error('上传失败'))
}
},
fail: (err) => {
reject(err)
}
})
})
}
/**
* 下载并打开文件,根据文件类型自动选择打开方式
* @param {string} url - 要下载的文件远程URL
*/
export const downloadFile = (url) => {
console.log('文件原始远程地址:', url)
const suffix = getFileExtension(url)
console.log('文件后缀为:', suffix)
const docSuffix = ['doc', 'xls', 'ppt', 'pdf', 'docx', 'xlsx', 'pptx']
const imgSuffix = ['jpg','jpeg','png','bmp','webp','tiff','tif','gif','svg','ai','raw','heic','heif','ico','eps','avif','jxr','hdp','xcf','psd','psb','drf','dng','xpm','pnm','ppm','pgm','pbm']
const fs = uni.getFileSystemManager()
removeTempFile(fs)
const downloadTask = uni.downloadFile({
url: url,
success: (res) => {
const fileName = res.tempFilePath.split('/').pop().split('#')[0].split('?')[0];
const localFilePath = `${uni.env.USER_DATA_PATH}/${fileName}`;
console.log('文件路径:', localFilePath);
if (docSuffix.includes(suffix)) {
uni.openDocument({
filePath: res.tempFilePath,
showMenu: true,
success: (res) => {
console.log('打开文档成功');
}
});
} else if (imgSuffix.includes(suffix)) {
uni.previewImage({
urls: [res.tempFilePath],
showMenu: true,
success: (res) => {
console.log('打开图片成功');
}
});
} else {
uni.$u.toast('图片不支持打开')
fs.saveFile({
tempFilePath: res.tempFilePath,
filePath: localFilePath,
success: (res) => {
uni.$u.toast('图片已保存到本地:', localFilePath)
},
fail: (err) =>{
console.log('保存失败', err)
},
complete: () => {
console.log('保存完成')
}
})
}
},
fail: (err) =>{
console.log('下载失败', err)
},
complete:() => {
console.log('下载完成')
}
})
downloadTask.onProgressUpdate((res) => {
console.log('下载进度:', res.progress)
uni.showLoading({
title: `下载中 ${res.progress}%`,
mask: true
})
if (res.progress === 100) {
uni.hideLoading()
}
})
}
/**
* 清理缓存中的临时文件
* @param {Object} fs - 文件系统管理器实例
*/
const removeTempFile = (fs) => {
fs.getSavedFileList({
success: (res) => {
console.log('缓存中的文件为:', res.fileList)
if (res.fileList.length > 0) {
for (let i = 0; i < res.fileList.length; i++) {
fs.removeSavedFile({
filePath: res.fileList[i].filePath,
success: (res) => {
console.log('删除成功', res)
},
fail: (err) =>{
console.log('删除失败', err)
},
complete: (res) => {
console.log('删除文件完成', res)
}
})
}
}
},
error: (res) => {
console.log('获取文件异常', res)
},
complete: (res) => {
console.log('获取文件完成')
}
})
}
/**
* 从URL中提取文件扩展名
* @param {string} url - 文件URL
* @returns {string} 文件扩展名(小写)
*/
function getFileExtension(url) {
return (url.match(/\.([^./]+)(?:[\?#]|$)/)?.[1] || '').toLowerCase();
}
html<view>
<up-upload
v-if="!withdrawRecord.invoiceUrl"
@afterRead="toUpload"
:maxCount="1"
width="250"
height="150"
/>
<view v-else class="image-container">
<image :src="withdrawRecord.invoiceUrl" style="width: 250px;height: 150px;" />
<up-icon class="close-icon" name="close" @click="remove" />
</view>
</view>
<script setup>
const toUpload = async(event) => {
uploadFile(event.file.url).then(url => {
withdrawRecord.value.invoiceUrl = url
})
}
</script>
本文详细介绍了Uniapp中文件上传下载工具的实现,包括:
这个工具类可以方便地集成到各种Uniapp项目中,满足基本的文件操作需求。开发者可以根据实际项目需求进行进一步定制和扩展。