uniapp 缓存请求文件时 判断是否有文件缓存 并下载和使用

fileCache.js

复制代码
// ========== 核心Promise函数 ==========

/**
 * 获取文件系统 (Promise封装)
 * @param {number} fsType - 文件系统类型,如 plus.io.PRIVATE_DOC
 * @returns {Promise<FileSystem>}
 */
function getFileSystem(fsType) {
	return new Promise((resolve, reject) => {
		plus.io.requestFileSystem(fsType, resolve, reject);
	});
}

/**
 * 确保目录存在,不存在则创建 (Promise封装)
 * @param {DirectoryEntry} root - 根目录Entry
 * @param {string} dirPath - 目录路径
 * @returns {Promise<DirectoryEntry>}
 */
function ensureDirectory(root, dirPath) {
	return new Promise((resolve, reject) => {
		root.getDirectory(dirPath, {
			create: false
		}, resolve, (error) => {
			console.log('dirPath', dirPath, error);
			if (error.code === 14) {
				console.log('dirPathOk', dirPath);
				root.getDirectory(dirPath, {
					create: true
				}, resolve, reject);
			} else {
				console.log('dirPathFF', dirPath);
				reject(new Error(`获取目录失败: ${error.message}`));
			}
		});
	});
}

/**
 * 检查文件是否存在并获取可用URL (Promise封装)
 * @param {string} filePath - 文件路径(如 "_doc/images/avatar.png")
 * @returns {Promise<{url: string, entry: FileEntry}>}
 */
function checkAndGetFileUrl(filePath) {
	return new Promise((resolve, reject) => {
		plus.io.resolveLocalFileSystemURL(filePath, (entry) => {
			const platformPath = plus.io.convertLocalFileSystemURL(entry.toURL());
			resolve({
				url: platformPath,
				entry
			});
		}, (error) => {
			reject(new Error(`文件不存在或无法访问: ${filePath} - ${error.message}`));
		});
	});
}

// 综合示例:下载文件到PRIVATE_DOC指定路径(Promise模式)
async function downloadFileToPrivateDoc(downloadUrl, saveFileName) {
	return new Promise((resolve, reject) => {
		// 1. 合成目标路径:_doc/downloads/ + 你指定的文件名
		const targetPath = `${saveFileName}`;

		// 2. 创建下载任务[citation:7]
		const downloadTask = plus.downloader.createDownload(
			downloadUrl, {
			filename: targetPath, // 关键:指定保存路径和文件名
			timeout: 120000 // 可选:设置超时时间(毫秒)
		},
			(download, status) => {
				// 3. 下载完成回调
				if (status === 200) {
					console.log('文件下载成功,临时保存于:', download.filename);

					// 4. 获取可用于img标签的file://路径[citation:6]
					const finalPath = plus.io.convertLocalFileSystemURL(download.filename);
					console.log('最终可用路径:', finalPath);

					resolve({
						fileEntry: download,
						savedPath: download.filename, // 如 _doc/downloads/myImage.jpg
						usableLocalUrl: finalPath // 如 file:///storage/emulated/0/Android/data/.../myImage.jpg
					});
				} else {
					reject(new Error(`下载失败,状态码: ${status}`));
				}
			}
		);

		// 5. 可选:监听下载进度[citation:1][citation:10]
		downloadTask.addEventListener('statechanged', (task, status) => {
			if (task.state === 3) { // 下载中
				const progress = task.totalSize > 0 ?
					Math.round((task.downloadedSize / task.totalSize) * 100) :
					0;
				console.log(`下载进度: ${progress}%`);
				// 这里可以更新UI进度条
			}
		});

		// 6. 开始下载任务[citation:7]
		downloadTask.start();
	});
}


function getFileNameFromUrl(url) {
	try {
		// 创建URL对象,自动处理完整URL
		const urlObj = new URL(url);
		// 获取路径部分,然后取最后一段
		const fileName = urlObj.pathname.split('/').pop();
		return fileName || ''; // 返回文件名,为空则返回空字符串
	} catch (e) {
		// 如果不是合法完整URL,尝试直接处理
		return url.split('/').pop().split('?')[0].split('#')[0];
	}
}

// ========== 综合使用示例 ==========
/* export async function handleFileOperations(dir,fileUrl) {
	try {
		// 1. 获取文件系统
		const fs = await getFileSystem(plus.io.PRIVATE_DOC);
		console.log('文件系统获取成功');

		// 2. 确保下载目录存在
		const downloadsDir = await ensureDirectory(fs.root, 'fileCache');
		console.log('目录已就绪:', downloadsDir.fullPath);

		// 3. 定义文件路径和远程URL
		//const remoteUrl = 'https://example.com/path/to/image.jpg';
		
		var fileName = getFileNameFromUrl(fileUrl);
		
		const targetFilePath = '_doc/fileCache/'+dir+"/"+fileName;
	    

		// 4. 检查文件是否已存在
		try {
			const { url: existingUrl } = await checkAndGetFileUrl(targetFilePath);
			// 更新图片显示
			// this.previewUrl = existingUrl;
			// existingUrl = `'${existingUrl}'`
			console.log('文件已存在,直接使用:', existingUrl);
			console.log(typeof existingUrl);
			return existingUrl;
		} catch (notExistError) {
			console.log('文件不存在,开始下载...');
		    
			// 5. 下载文件
			const fileEntry = await downloadFileToPrivateDoc(fileUrl, targetFilePath);
			console.log('文件下载完成:', fileEntry);

			// 6. 获取可用URL
			const { url: newUrl } = await checkAndGetFileUrl(targetFilePath);
			console.log('文件可用路径:', newUrl);
			// 更新图片显示
			// this.previewUrl = newUrl;
			return newUrl;
		}
	} catch (error) {
		console.error('操作失败:', error.message);
		throw error;
	}
} */



export function handleFileOperations(dir, fileUrl) {
	return new Promise((resolve, reject) => {
		// #ifdef WEB
		resolve(fileUrl);
		// #endif
		// #ifdef APP-PLUS
		getFileSystem(plus.io.PRIVATE_DOC)
			.then(fs => ensureDirectory(fs.root, 'fileCache'))
			.then(() => {
				const fileName = getFileNameFromUrl(fileUrl);
				const targetFilePath = '_doc/fileCache/' + dir + "/" + fileName;

				return checkAndGetFileUrl(targetFilePath)
					.then(({ url }) => {
						console.log('文件已存在,直接使用');
						resolve(url);
					})
					.catch(() => {
						console.log('文件不存在,开始下载');
						return downloadFileToPrivateDoc(fileUrl, targetFilePath)
							.then(() => checkAndGetFileUrl(targetFilePath))
							.then(({ url }) => {
								console.log('文件下载完成');
								resolve(url);
							});
					});
			})
			.catch(error => {
				console.error('操作失败:', error.message);
				reject(error);
			});
		// #endif
	});
}

调用 handleFileOperations 方法,传入本地缓存子目录,和问价url,会自动判断是否有缓存,有直接返回缓存本地路径,无则下载,并返回本地文件路径

main.js

复制代码
import { handleFileOperations } from '@/utils/fileCache.js';
Vue.prototype.$handleFileOperations = handleFileOperations;

使用示例

image-src.vue

复制代码
<template>
  <view>
    <image mode="aspectFill" :style="'width: '+ width +'; height: '+ height +';border-radius: ' + borderRadius + ';'" v-if="url && !error" :src="url" />
    <view v-if="loading">加载中...</view>
    <image v-if="error" :style="'width: '+ width +'; height: '+ height +';border-radius: ' + borderRadius + ';'" :src="errorImage" />
  </view>
</template>

<script>
export default {
  props: ['promiseFunc','interfacePath','width','height','borderRadius','errorImage'],
  data() {
    return { url: '', loading: true, error: false };
  },
  async mounted() {
    this.url = await this.$handleFileOperations(this.interfacePath,this.promiseFunc);
    // console.log('this.url',this.url);
	this.loading = false;
  }
}
</script>

使用 $handleFileOperations 可自动使用和下载缓存,并返回本地路径

相关推荐
Light6013 小时前
CSS逻辑革命:原生if()函数如何重塑我们的样式编写思维
前端·css·响应式设计·组件化开发·css if函数·声明式ui·现代css
蜡笔小嘟13 小时前
宝塔安装dify,更新最新版本--代码版
前端·ai编程·dify
web前端神器14 小时前
vue、uniapp项目循环中能显示每个列表的内容,但是点击的时候传递的参数却不正确
uni-app
ModyQyW14 小时前
HBuilderX 4.87 无法正常读取 macOS 环境配置的解决方案
前端·uni-app
bitbitDown14 小时前
我的2025年终总结
前端
五颜六色的黑14 小时前
vue3+elementPlus实现循环列表内容超出时展开收起功能
前端·javascript·vue.js
脾气有点小暴15 小时前
Uni-app App 端自定义导航栏完整实现指南
uni-app
wscats15 小时前
Markdown 编辑器技术调研
前端·人工智能·markdown
EnoYao15 小时前
Markdown 编辑器技术调研
前端·javascript·人工智能
JIngJaneIL15 小时前
基于java+ vue医院管理系统(源码+数据库+文档)
java·开发语言·前端·数据库·vue.js·spring boot