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 可自动使用和下载缓存,并返回本地路径