紧接 上一篇保存图片到相册 ,项目中还有一个根据条件导出 Excel 文件并要求保存到手机上的需求,接下来也将分别介绍 uni-app 及 H5+ 两种方案。
uni.webView.postMessage({
data: {
operType: 'saveFile',
url: 'http://www.test.com/exportExcel',
token: '123',
params: {
key1: 'value1',
key2: 'value2'
}
}
});
<template>
<view>
<web-view src="/hybrid/html/index.html" @message="handleMessage"></web-view>
</view>
</template>
<script>
export default {
methods: {
handleMessage(e) {
const [opts] = e.detail.data; // e.detail.data 得到的是一个消息数组
this.downloadFile(opts);
},
// 下载文件
downloadFile(opts) {
let {
url,
token,
operType,
params
} = opts;
if (params) url = url + JSON.stringify(params);
uni.downloadFile({
url,
// timeout: 30000, 超时时间
header: { token }, // 下载文件需要传递的请求头参数都设置在 header 对象中
success: res => {
const {
statusCode,
tempFilePath // 临时文件路径,下载后的文件会存储到一个临时文件
} = res;
console.log(tempFilePath);
if (statusCode === 200) {
console.log('下载文件成功');
if (operType === 'saveImg') {
this.saveImg(tempFilePath);
}
if (operType === 'saveFile') {
this.saveFile(tempFilePath);
}
} else {
uni.showToast({
title: '下载文件失败'
});
}
}
})
},
// 保存文件
saveFile(filePath) {
uni.saveFile({
tempFilePath: filePath,
success: (res) => {
uni.showToast({
title: '文件保存成功'
});
console.log('文件保存成功,路径为:' + res.savedFilePath)
},
fail: (err) => {
console.log('文件保存失败:' + err)
}
})
},
}
}
</script>
因为 uni.downloadFile 只支持 get 请求,原本导出 Excel 的后端请求是 post,参数都放在 body 中,与后端协商之后改为 get 方式,参数使用 url 中的 params 接收一个经过 JSON.stringify 转换的对象字符串。
uni.saveFile 保存成功之后,但无法设置文档的存放位置,而实际文档存放的位置对于用户来说又比较难找到,比如这是一个用 HBuilderX + 夜神模拟器调试 时打印的存储路径:
/storage/emulated/0/Android/data/io.dcloud.HBuilder/apps/HBuilder/doc/uniapp_save/17038344728620.xls
将保存文档的操作修改为了打开文档,打开文档之后用户可自行通过wx等分享此文档。以下为修改之后的代码:
<template>
<view>
<web-view src="/hybrid/html/index.html" @message="handleMessage"></web-view>
</view>
</template>
<script>
export default {
methods: {
handleMessage(e) {
const [opts] = e.detail.data; // e.detail.data 得到的是一个消息数组
this.downloadFile(opts);
},
// 下载文件
downloadFile(opts) {
let {
url,
token,
operType,
params
} = opts;
if (params) url = url + JSON.stringify(params);
uni.downloadFile({
url,
// timeout: 30000, 超时时间
header: { token }, // 下载文件需要传递的请求头参数都设置在 header 对象中
success: res => {
const {
statusCode,
tempFilePath // 临时文件路径,下载后的文件会存储到一个临时文件
} = res;
console.log(tempFilePath);
if (statusCode === 200) {
console.log('下载文件成功');
if (operType === 'saveImg') {
this.saveImg(tempFilePath);
}
if (operType === 'saveFile') {
// this.saveFile(tempFilePath);
this.openFile(tempFilePath);
}
} else {
uni.showToast({
title: '下载文件失败'
});
}
}
})
},
// 保存文件
saveFile(filePath) {
uni.saveFile({
tempFilePath: filePath,
success: (res) => {
uni.showToast({
title: '文件保存成功'
});
console.log('文件保存成功,路径为:' + plus.io.convertLocalFileSystemURL(res.savedFilePath));
},
fail: (err) => {
console.log('文件保存失败:' + err);
}
})
},
// 打开文档
openFile(filePath) {
let platform = uni.getSystemInfoSync().platform; //当前环境
if (platform == 'ios') {
filePath = escape(filePath);
}
uni.openDocument({
filePath,
showMenu: true,
success: function(res) {
console.log('打开文档成功');
},
fail: function(e) {
console.log(e);
uni.showToast({
title: '打开失败'
})
}
});
},
}
}
</script>
针对 ios 系统将 filepath 经过 escape() 转换
之后就可正常打开let params: {
key1: 'value1',
key2: 'value2'
}
let url = `http://www.test.com/exportExcel?params=${JSON.stringify(params)}`
let fileName = '测试.xls'
let options = {
filename: `_downloads/${fileName}`,
// timeout: 120 // 超时时间单位s,默认120s
}
let header = {
token: '123'
}
plusDownloadFile(url, options, header)
// H5下载文件
plusDownloadFile(url, options = {}, header = {}) {
let dtask = plus.downloader.createDownload(url, options, (d, status) => {
if (status == 200) {
this.$showToast.ok( '下载成功' );
console.log('文件存储路径:' + d.filename);
// 调用打开文件方法
plus.runtime.openFile(options.filename);
} else {
this.$showToast.error('下载失败');
plus.downloader.clear();
}
});
Object.keys(header).forEach(k => {
dtask.setRequestHeader(k, header[k]);
});
// 开始下载
dtask.start();
},