实现微信小程序web-view内嵌H5中的下载功能(大文件切片下载)

这篇具有很好参考价值的文章主要介绍了实现微信小程序web-view内嵌H5中的下载功能(大文件切片下载)。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

一、项目场景:

微信小程序的开发框架是uniapp,使用uniapp脚手架搭建,其中有页面是展示另一个小程序,在这个页面主体内容使用了标签将H5的页面内容展示,H5中有页面存放了下载的路径。点击下载按钮下载文件,或者预览文件让用户手动保存。

难点

  • 如果是pc端,下载用一个<a>标签就很容易,但是在小程序里的标签中是行不通的。
  • 此外,小程序里的<web-view>与小程序的通行方式主要用postMessage,但是触发条件非常苛刻,参照微信的官方文档,只在小程序后退组件销毁,还有分享时才会触发postMessage并一次性把值全部带出来,使用起来非常不便,对于小程序实际内容主体是<web-view>内嵌的spa的H5页面的情况下,销毁组件会带来很多麻烦,因此最后放弃了这个方案

解决方案:

1、H5微信小程序:

a、首先必不可少的是安装jweixin-module模块:
npm i jweixin-module
b、在main.js中将依赖绑定:
import wx from  "jweixin-module"
Vue.prototype.$wx = wx 
c、H5对应页面点击下载时代码为:
this.$wx.miniProgram.navigateTo({
  url:"/pages/study/downLoading?url="+encodeURIComponent(fileInfo.content_url) 
})

2、uni-app的小程序

a、对应的/pages/study/downLoading页面
<template> <div>下载中。。。</div> </template>
<script lang="ts" setup>
import { onLoad } from '@dcloudio/uni-app';
onLoad((option: any) => {
  console.log('gfdjhwghjghjkjghjklghjk', option.url);
  handleDown(decodeURIComponent(option.url));
});
const handleDown = (url: string) => {
  uni.showLoading({
    title: '下载中', //提示文字
    mask: true, //是否显示透明蒙层,防止触摸穿透,默认:false
  });
  console.log(url);
  let imageType = ['gif', 'png', 'jpg', 'tif', 'bmp', 'webp', 'jpeg', 'JPG'];
  const downloadTask = uni.downloadFile({
    url: url,
    success: res => {
      console.log(res, 'resresresres');
      uni.hideLoading();
      if (res.statusCode === 200) {
        console.log(res.tempFilePath, '1111111');
        let originFileNameSplit = res.tempFilePath.split('.');
        let fileNameType = originFileNameSplit[originFileNameSplit.length - 1];
        uni.getFileSystemManager().saveFile({
          //微信保存文件,这个存储有点复杂
          // 临时存储路径,先有临时存储路径方可使用wx官方的存储本地路径( uni.env.USER_DATA_PATH )
          tempFilePath: res.tempFilePath,
          //定义本地的存储路径及名称
          success(res) {
            const savedFilePath = res.savedFilePath;
            uni.setStorageSync('uploadData', savedFilePath); //保存传入的参数
            uni.setStorageSync('isImageType', imageType.includes(fileNameType)); //保存传入的参数
            uni.hideLoading();
            uni.navigateBack({
              delta: 1,
            });
          },
          fail(err) {
            uni.showToast({
              title: '预览失败',
              icon: 'error',
              duration: 1500,
            });
            setTimeout(() => {
              uni.navigateBack({
                delta: 1,
              });
            }, 3000);
          },
        });
      }
    },
    fail: err => {
      uni.hideLoading();
      uni.showToast({
        title: '下载失败',
        icon: 'error',
        duration: 1500,
      });
      console.log(err);
      setTimeout(() => {
        uni.navigateBack({
          delta: 1,
        });
      }, 3000);
    },
  });
  downloadTask.onProgressUpdate(res => {
    // console.log('下载进度', res.progress);
    // console.log('已经下载的数据长度', res.totalBytesWritten);
    // console.log('预期需要下载的数据总长度', res.totalBytesExpectedToWrite);
  });
};
</script>
b、可以预览的时候返回到web-view页面:
<template>
  <view class="study">
    <web-view class="webviewOut" :src="你的url地址"></web-view>
  </view>
</template>

<script setup lang="ts">
onShow(() => {
  const url = uni.getStorageSync('uploadData');
  console.log('1111111111111111111111111111111111', url);
  if (url) {
    uni.hideHomeButton();
    handleDown(url); //具体的微信下载文件的方法
    //每次onShow执行完,还有上面的下载方法执行完后要把这个标记重置为false,这样不同情况触发的onShow才能区分是否是下载文件页面回来的。可能写的重复但是多写几次比较放心
  }
});
const handleDown = (savedFilePath: string) => {
  const isImageType = uni.getStorageSync('isImageType');
  if (isImageType) {
    uni.previewImage({
      urls: [savedFilePath],
      success: function (res) {
        uni.removeStorageSync('uploadData');
        uni.removeStorageSync('isImageType');
      },
      fail: function (err) {
        console.log(res);
        uni.showToast({
          title: '预览失败',
          icon: 'error',
          duration: 1500,
        });
        uni.removeStorageSync('uploadData');
        uni.removeStorageSync('isImageType');
      },
    });
  } else {
    uni.openDocument({
      //微信打开文件
      filePath: savedFilePath,
      showMenu: true,
      success: function (res) {
        uni.removeStorageSync('uploadData');
        uni.removeStorageSync('isImageType');
      },
      fail: function (err) {
        console.log(res);
        uni.showToast({
          title: '预览失败',
          icon: 'error',
          duration: 1500,
        });
        uni.removeStorageSync('uploadData');
        uni.removeStorageSync('isImageType');
      },
    });
  }
};
</script>

<style scoped lang="scss">
.study {
  height: 100vh;
  box-sizing: border-box;
  padding-bottom: 98rpx;
}
</style>

二、注意(下载大文件)

uni.downloadFile 主要包含两个参数:urlfilePath,其中 url 代表下载文件的路径,filePath 代表下载文件保存的路径。
uni.downloadFile 可以用来下载较小的文件,但是对于大文件的下载需要通过 分片下载方式 。具体来说,可以使用 uni.downloadFile 和 uni.uploadFile 结合使用实现分片下载。同时,需要注意为下载文件分配足够的存储空间,以便能够完整保存整个文件。

具体步骤如下:

1.获取文件的总大小。

uni.request({
    url: 'http://example.com/fileUrl',
    method: 'HEAD',
    success: function (res) {
        let contentLength = res.header['Content-Length'];
        // 计算出下载总块数
        let blockCount = Math.ceil(contentLength / BLOCK_SIZE);
        // 创建一个和块数相同的数组
        let blockList = new Array(blockCount).fill(0);
        // 进行分块下载
        downloadFileByBlock(url, savePath, blockList);
    }
});

2.将文件分成若干个块(BLOCK_SIZE 为每个块的大小),以便分批下载。

3.循环下载每一块。

function downloadFileByBlock(url, savePath, blockList) {
    blockList.forEach(function (v, i) {
        let rangeStart = i * BLOCK_SIZE;
        let rangeEnd = (i + 1) * BLOCK_SIZE - 1;
        // 利用 Range 请求头指定下载区间
        uni.downloadFile({
            url: url,
            filePath: savePath,
            header: {
                'Range': 'bytes=' + rangeStart + '-' + rangeEnd
            },
            success: function (res) {
                console.log(res);
            },
            fail: function (err) {
                console.log(err);
            }
        });
    });
}

大文件上传也可以采用类似的方式, 即将文件分成若干块,每次上传一个块,直到上传完整个文件。

完整代码(自己改了改)

这里给出针对微信小程序 web-view 内嵌 H5 中大文件切片下载的完整代码实现:

// download.js

const downloadUrl = 'http://example.com/files/file.zip' // 下载地址
const fileName = 'file.zip' // 下载的文件名
const fileSize = 1024 * 1024 * 100 // 文件大小,100MB
const chunkSize = 1024 * 1024 * 2 // 分片大小,2MB
const tempFilePath = wx.env.USER_DATA_PATH + '/downloads/' // 临时文件存储路径

Page({
  data: {
    progress: 0, // 下载进度
    isDownloading: false, // 是否正在下载
    downloadTask: null // 下载任务句柄
  },

  // 开始下载
  startDownload() {
    if (this.data.isDownloading) {
      return
    }
    this.setData({ isDownloading: true })
    this.downloadChunks()
  },

  // 取消下载
  cancelDownload() {
    if (this.data.downloadTask) {
      this.data.downloadTask.abort()
    }
    this.resetState()
  },

  // 处理分片下载任务队列,完成后进行合并操作
  downloadChunks() {
    const chunkNum = Math.ceil(fileSize / chunkSize)
    const chunks = []
    for (let i = 0; i < chunkNum; i++) {
      const start = i * chunkSize
      const end = Math.min(start + chunkSize, fileSize)
      chunks.push({
        index: i,
        start,
        end,
        downloaded: false,
        filePath: `${tempFilePath}${i}`
      })
    }

    // 进度状态:已下载的字节数
    let loadedBytes = 0

    // 下载分片
    const downloadChunk = (chunk) => {
      return new Promise((resolve, reject) => {
        const downloadTask = wx.downloadFile({
          url: downloadUrl,
          header: {},
          filePath: chunk.filePath,
          success: (res) => {
            if (res.statusCode === 200) {
              loadedBytes += chunk.end - chunk.start + 1
              chunk.downloaded = true
              resolve()
            } else {
              reject(new Error('Download chunk error.'))
            }
          },
          fail: () => {
            reject(new Error('Download chunk fail.'))
          }
        })
        downloadTask.onProgressUpdate((res) => {
          const progress = Math.floor((loadedBytes + res.totalBytesWritten) / fileSize * 100)
          console.log('分片下载进度:', progress)
          this.setData({ progress })
        })
        this.setData({ downloadTask })
      })
    }

    Promise.all(chunks.map(downloadChunk))
      .then(() => {
        this.mergeFiles()
      })
      .catch((err) => {
        console.log(err)
        this.resetState()
      })
  },

  // 合并已下载的分片文件
  mergeFiles() {
    const fs = wx.getFileSystemManager()
    const stream = fs.createWriteStream(`${wx.env.USER_DATA_PATH}/downloads/${fileName}`)

    const write = (index) => {
      const chunk = chunks[index]
      if (!chunk.downloaded) {
        console.log(`Chunk ${chunk.index} not downloaded.`)
        return
      }
      fs.readFile(chunk.filePath, 'binary', (err, data) => {
        if (err) {
          console.log(err)
          return
        }
        stream.write(data, 'binary')
        if (index < chunks.length - 1) {
          write(index + 1)
        } else {
          // 文件合并完成
          stream.end()
          this.resetState()
        }
      })
    }

    write(0)
  },

  // 重置下载状态
  resetState() {
    this.setData({
      progress: 0,
      isDownloading: false,
      downloadTask: null
    })
  }
})

在 H5 页面中可以引入此文件作为下载操作的逻辑处理。同时还需要在 wxml 文件中添加下载按钮及进度条,代码如下:

<!-- download.wxml -->

<view class="download-container">
  <button class="download-btn" bindtap="startDownload">下载</button>
  <progress percent="{{ progress }}%" />
</view>

需要在小程序的 app.json 文件中添加下载临时路径配置,代码如下:

抱歉,似乎代码显示出现了截断,请继续查看完整的 app.json 中的配置:

{
  "pages": [
    "pages/index/index",
    "pages/download/download"
  ],
  "permission": {
    "scope.userLocation": {
      "desc": "小程序将获取您的定位信息"
    }
  },
  "downloadFile": {
    "domain": [ "example.com" ],
    "timeout": 10000
  },
  "subpackages": []
}

其中,downloadFile 字段下对应了下载文件的配置,包括限定下载域名、超时时间等。文件下载的域名必须在此处进行配置,否则会被微信限制,无法正常下载。

总结:

大致过程就是这样,网上有很多解决方案都是在uni-app小程序的loading页面直接去缓存一下h5发过来的下载地址之后,直接返回到web-view页面去进行下载预览,他的 缺点点击下载时页面会一闪而过空白的微信页面再回来,我把下载直接放到了downLoading页面就是为了可以告诉用户我已经在下载了,可以给用户一点好的体验。

uni.navigateBack({delta: 1}); 返回到web-view的目的是为了你在预览界面点击左上角返回时可以回到web-view页面,直接下载预览都在downLoading页面的话,你在预览页面点击返回就会回到downLoading页面,体验不是很好。文章来源地址https://www.toymoban.com/news/detail-499432.html

到了这里,关于实现微信小程序web-view内嵌H5中的下载功能(大文件切片下载)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 微信小程序web-view环境下H5跳转小程序页面方法

    一般的,web-view组件的src属性指定的H5页面之间,可以正常的采用超级链接a标记对进行页面之间的条转。但是web-view页面要想通过手指触碰返回小程序页面,就无法使用超级链接a标记了。那么这个问题应该如何解决呢? 首先需要在H5页面中引入JSSDK,它可以让H5页面的js文件执

    2024年01月17日
    浏览(73)
  • uniapp微信小程序在web-view嵌入的uniapp H5页面中预览word文件

    在小程序中预览文件可以使用uni.uploadFile下载后再uni.openDocument打开预览,但uni.openDocument API是不支持H5的,这时候可能会想到使用微软在线预览,但是实际出来的效果会存在各种兼容性问题。因此我们需要在h5页面中跳回小程序然后走小程序的预览文件逻辑。

    2024年02月11日
    浏览(67)
  • 微信小程序web-view嵌入uni-app H5页面,通过H5页面跳转其他小程序如何操作?

     微信小程序appId查看方法: 1)有后台登录权限的情况下:登录微信公众平台后, 微信公众平台 微信公众平台,给个人、企业和组织提供业务服务与用户管理能力的全新服务平台。 https://mp.weixin.qq.com/ 点击右上角logo,在“帐号信息”中找到AppID(小程序ID) 2)没有后台登录权

    2024年02月11日
    浏览(81)
  • 微信小程序web-view嵌入uni-app H5页面,通过H5页面跳转企业微信客户聊天窗口如何操作?

    1)找到企业ID,登录 企业微信 企业微信 https://work.weixin.qq.com/wework_admin/loginpage_wx  2)找到接入链接  功能-客服-微信客服 微信公众平台,给个人、企业和组织提供业务服务与用户管理能力的全新服务平台。 https://mp.weixin.qq.com/

    2024年02月11日
    浏览(68)
  • 微信小程序实现支付宝支付——web-view实现

    由于使用到的微信小程序需要实现支付功能,而微信支付的申请手续较为繁琐,所以使用了支付宝支付,但是微信小程序正常情况不支持支付宝支付,所以我使用了web-view内嵌了支付宝的h5支付。 不会使用支付宝沙箱支付的同学可以看这篇文章Springboot支付宝沙箱支付 代码如下

    2024年02月11日
    浏览(59)
  • 微信小程序学习实录5(H5嵌入小程序、map组件、地图调起功能、腾讯百度高德导航页、返回web-view页)

    创建容器 地图家长 在H5页面引入 //res.wx.qq.com/open/js/jweixin-1.6.0.js ,建议使用高版本; 点击返回按钮 调用微信小程序和H5通用API 判断是否在微信小程序环境中 地图调起,再次返回小程序页 获取H5传递参数的方式为: console.log(options) latitude和longitude必须为数字类型,不支持字符

    2024年02月07日
    浏览(95)
  • 微信小程序web-view嵌入uni-app H5页面,通过H5页面传参给小程序进行转发分享页面,并通过点击转发出来的卡片,定向打开对应H5路径

    index.wxml  index.js 在H5项目的App.vue页面获取参数实现自动跳转到对应页面,包括携带的参数值

    2024年02月12日
    浏览(74)
  • 微信小程序web-view跳转

    h5项目中跳转外部连接可使用的web-view标签解决 官网连接:web-view | 微信开放文档 1.添加事件 2.新页面中的跳转链接(一行即可,默认会会自动铺满整个小程序页面) src就是路径,写需要跳转的网页地址即可! 3.配置路由,app.jason中 4.小程序后台配置域名 开发管理=开发设置=业务域名中

    2024年02月11日
    浏览(69)
  • 微信小程序如何使用web-view

           有时我们的业务需求是小程序内部跳转到其他h5项目的页面,这是我们就会用到web-view标签,这个标签可以帮助我们完成h5页面的渲染。下面,就是使用方法: 第一步: 首先现在小程序建一个新的page用来使用web-view  在wxml文件中写入web-view标签,src属性为你要跳转h5线

    2024年02月14日
    浏览(56)
  • 小程序使用web-view内嵌跳转另一个小程序

    1、配置需要跳转的小程序地址和参数,直接跳转 2、新建一个h5Pages.vue文件使用web-view内嵌需要跳转的小程序界面 html部分: js部分: 3、可能需要对方小程序配置安全域名

    2024年02月09日
    浏览(53)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包