引言
在移动应用开发中,文件管理是一个常见但复杂的需求,不同平台对文件系统的访问方式存在显著差异。UniApp作为跨平台开发框架,提供了一套统一的API来处理文件操作,大大简化了多平台适配工作。本文将带领大家开发一个功能完整的跨平台文件管理器,涵盖文件浏览、上传、下载、预览等核心功能。
一、项目初始化与结构设计
1. 创建UniApp项目
使用HBuilder X创建新的uni-app项目,选择默认模板:
项目结构: ├── pages │ ├── index │ │ ├── index.vue # 主页面 │ │ └── file-preview.vue # 文件预览页 │ └── manager │ └── manager.vue # 文件管理页 ├── static │ ├── icons # 文件类型图标 │ └── images # 静态图片 ├── uni_modules # uni模块 ├── App.vue # 应用配置 └── manifest.json # 应用配置文件
2. 文件类型识别工具
创建文件类型识别工具类,用于显示不同类型的文件图标:
// utils/file-util.js export default { // 获取文件类型图标 getFileIcon(filename) { const extension = filename.split('.').pop().toLowerCase(); const iconMap = { 'pdf': 'pdf-icon.png', 'doc': 'word-icon.png', 'docx': 'word-icon.png', 'xls': 'excel-icon.png', 'xlsx': 'excel-icon.png', 'jpg': 'image-icon.png', 'jpeg': 'image-icon.png', 'png': 'image-icon.png', 'mp4': 'video-icon.png', 'mp3': 'audio-icon.png', 'zip': 'archive-icon.png', 'rar': 'archive-icon.png' }; return iconMap[extension] || 'file-icon.png'; }, // 格式化文件大小 formatFileSize(bytes) { if (bytes === 0) return '0 B'; const k = 1024; const sizes = ['B', 'KB', 'MB', 'GB']; const i = Math.floor(Math.log(bytes) / Math.log(k)); return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + ' ' + sizes[i]; } };
二、核心功能实现
1. 文件列表展示组件
创建可复用的文件列表组件,支持多种布局方式:
<template> <view> <view class="file-list"> <view v-for="(file, index) in files" :key="index" class="file-item" @click="onFileClick(file)" > <image :src="getFileIcon(file.name)" class="file-icon" /> <view class="file-info"> <text class="file-name">{{ file.name }}</text> <text class="file-size">{{ formatFileSize(file.size) }}</text> <text class="file-date">{{ formatDate(file.modifiedTime) }}</text> </view> <view class="file-actions"> <button @click.stop="onDownload(file)">下载</button> <button @click.stop="onDelete(file)">删除</button> </view> </view> </view> </view> </template> <script> import fileUtil from '@/utils/file-util.js'; export default { props: { files: { type: Array, default: () => [] } }, methods: { getFileIcon(filename) { return fileUtil.getFileIcon(filename); }, formatFileSize(size) { return fileUtil.formatFileSize(size); }, formatDate(timestamp) { return new Date(timestamp).toLocaleDateString(); }, onFileClick(file) { this.$emit('file-click', file); }, onDownload(file) { this.$emit('download', file); }, onDelete(file) { this.$emit('delete', file); } } }; </script>
2. 文件上传功能
实现多文件选择和上传功能,支持进度显示:
<template> <view> <button @click="chooseFiles">选择文件</button> <view v-for="(file, index) in uploadQueue" :key="index"> <text>{{ file.name }}</text> <progress :percent="file.progress" show-info></progress> </view> </view> </template> <script> export default { data() { return { uploadQueue: [] }; }, methods: { async chooseFiles() { try { const res = await uni.chooseFile({ count: 10, type: 'all' }); res.tempFiles.forEach(file => { this.uploadFile(file); }); } catch (error) { uni.showToast({ title: '文件选择失败', icon: 'none' }); } }, async uploadFile(file) { const uploadTask = { name: file.name, size: file.size, progress: 0 }; this.uploadQueue.push(uploadTask); try { const uploadRes = await uni.uploadFile({ url: 'https://your-api-domain.com/upload', filePath: file.path, name: 'file', formData: { 'fileName': file.name }, success: (res) => { const data = JSON.parse(res.data); if (data.success) { uploadTask.progress = 100; uni.showToast({ title: '上传成功' }); } }, fail: (error) => { uni.showToast({ title: '上传失败', icon: 'none' }); } }); uploadTask.uploadTask = uploadRes; // 监听上传进度 uploadRes.onProgressUpdate((res) => { uploadTask.progress = res.progress; }); } catch (error) { console.error('Upload error:', error); } } } }; </script>
3. 文件下载与预览
实现文件下载功能,并支持常见格式的预览:
export default { methods: { async downloadFile(file) { uni.showLoading({ title: '下载中...' }); try { const result = await uni.downloadFile({ url: file.url, success: (res) => { if (res.statusCode === 200) { // 保存文件到本地 uni.saveFile({ tempFilePath: res.tempFilePath, success: (saveRes) => { uni.hideLoading(); uni.showToast({ title: '下载成功' }); this.$emit('download-complete', saveRes.savedFilePath); } }); } } }); } catch (error) { uni.hideLoading(); uni.showToast({ title: '下载失败', icon: 'none' }); } }, previewFile(file) { const extension = file.name.split('.').pop().toLowerCase(); const previewableTypes = ['pdf', 'jpg', 'jpeg', 'png', 'gif', 'txt']; if (previewableTypes.includes(extension)) { uni.navigateTo({ url: `/pages/index/file-preview?fileUrl=${encodeURIComponent(file.url)}&fileName=${encodeURIComponent(file.name)}` }); } else { uni.showModal({ title: '提示', content: '该文件格式不支持预览,是否下载?', success: (res) => { if (res.confirm) { this.downloadFile(file); } } }); } } } };
三、平台特定适配
1. 安卓文件系统权限处理
Android平台需要处理文件系统权限:
// #ifdef APP-PLUS async checkAndroidPermission() { try { const result = await uni.authorize({ scope: 'scope.writePhotosAlbum' }); return true; } catch (error) { // 权限未授予,请求权限 const settingResult = await uni.showModal({ title: '权限申请', content: '需要存储权限才能保存文件', confirmText: '去设置' }); if (settingResult.confirm) { uni.openAppAuthorizeSetting(); } return false; } } // #endif
2. iOS文件存储策略
iOS平台使用不同的文件存储策略:
// #ifdef APP-PLUS && OS_IOS getIOSDocumentDirectory() { return new Promise((resolve, reject) => { plus.io.requestFileSystem(plus.io.PRIVATE_DOC, (fs) => { resolve(fs.root.fullPath); }, reject); }); } // #endif
四、性能优化与最佳实践
1. 虚拟列表优化
对于大量文件,使用虚拟列表提升性能:
// 使用uni-app的scroll-view结合自定义虚拟列表 <scroll-view scroll-y :style="{ height: scrollHeight + 'px' }" @scroll="onScroll" > <view :style="{ height: totalHeight + 'px' }"> <view v-for="item in visibleItems" :key="item.id" :style="{ transform: `translateY(${item.offset}px)` }" > <!-- 文件项内容 --> </view> </view> </scroll-view>
2. 文件缓存机制
实现文件缓存以减少重复下载:
class FileCache { constructor() { this.cache = new Map(); this.maxSize = 50 * 1024 * 1024; // 50MB this.currentSize = 0; } async getFile(url) { if (this.cache.has(url)) { return this.cache.get(url); } const file = await this.downloadAndCache(url); return file; } async downloadAndCache(url) { // 下载文件并添加到缓存 // 如果超过最大缓存大小,清理最旧的文件 while (this.currentSize > this.maxSize) { this.removeOldest(); } } removeOldest() { // 实现LRU缓存淘汰算法 } }
五、测试与发布
1. 多平台测试策略
制定全面的测试计划:
- Android真机测试:文件权限、存储访问
- iOS真机测试:沙盒文件系统、相册访问
- 微信小程序测试:文件大小限制、API兼容性
- H5测试:浏览器文件API兼容性
2. 发布注意事项
各平台发布前的准备工作:
- Android:配置文件访问权限,处理动态权限申请
- iOS:配置相册访问描述,处理隐私权限
- 小程序:配置服务器域名,处理文件大小限制
- H5:配置HTTPS,处理浏览器兼容性
结语
通过本教程,我们完成了一个功能完整的跨平台文件管理器应用。这个项目展示了UniApp在处理复杂文件操作方面的强大能力,以及如何通过统一的API适配不同平台的特性。在实际开发中,还需要根据具体业务需求进一步完善错误处理、用户体验优化等功能。
UniApp的跨平台特性使得开发者可以用一套代码满足多个平台的需求,大大提高了开发效率。希望本文能够帮助读者深入理解UniApp文件操作的相关技术,并在实际项目中灵活运用。