功能需求背景:
项目开发中的需求,需在移动H5实现明细等列表导出下载功能,又因项目用户大多运行于微信内浏览器,而微信浏览器禁止下载行为,需引导用户跳转第三方浏览器完成下载。
功能实现思路:
- 前端发送导出请求
- 后端根据请求条件筛选数据生成CSV文件
- 后端提供"导出记录列表"接口,给到前端生成成功或失败状态以及下载地址
- 前端根据用户运行环境(微信内浏览器或者外部浏览器),引导用户完成报表下载
流程图
文件下载流程.png
使用技术栈
uniApp(vue2) + uview(1.X版本)
(本文主要讲解功能实现,页面样式表不另外提供哈)
目录结构如下
image.png实现代码
公共函数
// 本人项目中,已注入Vue原型链的$m,故下方代码通过this.$m.isWxBrowser()与this.$m.isIos()调用
export const isWxBrowser = () => {
// 判断是否H5微信环境,true为微信浏览器
const ua = navigator.userAgent.toLowerCase()
return ua.match(/MicroMessenger/i) == 'micromessenger' ? true : false
}
export const isIos = ()=> {
// 是否IOS true为ios
let u = navigator.userAgent
let isIOS = !!u.match(/\(i[^;]+;( U;)? CPU.+Mac OS X/)
return isIOS ? true : false
}
页面 pages.json 配置
"subPackages": [
{
"root": "pagesA",
"pages": [
{
"path": "upLoad/exportLists",
"style": {
"navigationBarTitleText": "导出记录",
"enablePullDownRefresh": true
}
},
{
"path": "upLoad/uploadFile",
"style": {
"navigationBarTitleText": "下载",
}
}
]
}
],
pagesA/upLoad/exportLists 导出记录页面
<template>
<view class="page">
<u-alert-tips show-icon type="warning" title="下拉可更新导出状态"></u-alert-tips>
<view class="list">
<view class="mt-10" v-for="(item, i) in lists" :key="item.id">
<view class="list-item flex justify-between align-center">
<view class="item-info flex-sub flex flex-column justify-between">
<view class="time text-14">文件名:{{ item.file_name }}</view>
<view class="time text-14">状态:{{ item.status_text }}</view>
<view class="time text-14">创建时间:{{ item.created_at }}</view>
</view>
<u-button v-if="item.status == 1" style="margin: 0;" shape="square" type="error" size="mini" @click="downFile(item.url)">下载</u-button>
</view>
</view>
</view>
</view>
</template>
<script>
import { downLoadFile } from './uploadFun';
export default {
name: 'exportLists',
data() {
return {
lists: [
{
created_at: "2022-12-03 15:11:57",
file_name: "文件下载测试",
id: 1,
status: 1,
status_text: "已完成",
url: "https://xxx.com/settlement_2022-12-03_15_11_59.csv", // 文件下载地址
}
]
};
},
methods: {
downFile(url){
if(this.$m.isWxBrowser()) {
// 微信浏览器引导到文件下载页去
var local = encodeURIComponent(url); // 当前H5页面的url
this.$m.jump(`/pagesA/upLoad/uploadFile?url=${local}`) // 封装的跳转,同uni.navigateTo();
} else {
// 调用下载函数
downLoadFile(url)
}
},
}
}
</script>
pagesA/upLoad/uploadFile 下载页
<template>
<view>
<view class="main flex flex-column align-center justify-center">
<template v-if="fileUrl">
<view class="text text-center text-16 text-bold" v-if="fileName">{{ fileName }}</view>
<u-button class="download-btn mt-30" shape="square" type="primary" @click="downFile()">下载文件</u-button>
</template>
<u-empty v-else text="下载地址错误" mode="data"></u-empty>
</view>
</view>
</template>
<script>
import { downLoadFile } from './uploadFun';
export default {
name: 'downLoadFile',
data() {
return {
isWx: this.$m.isWxBrowser(), // 是否微信内部浏览器
fileUrl: '',
fileName: ''
};
},
onLoad(options) {
if(options && options.url){
this.fileUrl = decodeURIComponent(options.url); // 文件下载地址
let urlArrLength = this.fileUrl.split('/').length;
this.fileName = this.fileUrl.split('/')[urlArrLength - 1]; // 文件名
this.wxBrowserModal();
}
},
methods: {
wxBrowserModal() {
// 统一处理微信浏览器提示
if(this.isWx) {
// 此处提示可自行优化,比如遮罩层加引导图引导用户操作跳转
uni.showModal({
title: '提示',
content: '请点击右上角,在浏览器打开页面下载。',
showCancel: false
})
}
return !this.isWx // 方便downFile方法使用,return false停止执行下载
},
downFile() {
this.wxBrowserModal() && downLoadFile(this.fileUrl)
}
},
}
</script>
<style lang="scss" scoped>
.main {
position: fixed;
width: 100%;
height:100vh;
}
.download-btn {
width:50%;
}
</style>
uploadFun.js 文件
import { isIos } from '@/utils/util'; // 导入公共函数isIos(),代码已在上方"公共函数"提供
// csv文件下载
export const downLoadFile = (fileUrl)=> {
if(isIos()) {
// ios系统
// 通过链接获取文件名
let urlArrLength = fileUrl.split('/').length,
fileName = fileUrl.split('/')[urlArrLength - 1]; // 文件名
uni.showLoading({
title: "正在请求数据"
});
uni.request({
url: fileUrl, //获取文件流的请求路径
responseType: "arraybuffer",
success: (response) => {
uni.hideLoading();
if (!response) {
uni.showToast({
title: "下载失败",
duration: 2000
});
return
}
let blob = new Blob([response.data])
let downloadElement = document.createElement("a")
let href = window.URL.createObjectURL(blob) //创建下载的链接
downloadElement.href = href
downloadElement.download = fileName //下载后文件名
document.body.appendChild(downloadElement)
downloadElement.click() //点击下载
uni.showToast({
title: "下载成功",
duration: 2000
})
document.body.removeChild(downloadElement) //下载完成移除元素
window.URL.revokeObjectURL(href) //释放掉blob对象
}
})
} else {
// 安卓系统及其他
window.open(url)
}
}
列表页效果图
image.png
下载页效果图
下载页效果图.png
微信内部浏览器会弹出提示
微信内部浏览器弹出提示.png
网友评论