2022-12-06 uniApp H5端实现下载文件(包含微信浏览器内处理)

功能需求背景:

项目开发中的需求,需在移动H5实现明细等列表导出下载功能,又因项目用户大多运行于微信内浏览器,而微信浏览器禁止下载行为,需引导用户跳转第三方浏览器完成下载。

功能实现思路:

  1. 前端发送导出请求
  2. 后端根据请求条件筛选数据生成CSV文件
  3. 后端提供"导出记录列表"接口,给到前端生成成功或失败状态以及下载地址
  4. 前端根据用户运行环境(微信内浏览器或者外部浏览器),引导用户完成报表下载
流程图
文件下载流程.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
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容