当前位置: 首页 > news >正文

微信小程序文件下载与预览功能实现详解

在微信小程序开发中,文件处理是常见需求,尤其是涉及合同、文档等场景。本文将通过一个实际案例,详细讲解如何实现文件的下载、解压、列表展示及预览功能。

功能概述

该页面主要实现了以下核心功能:

  • 列表展示可下载的文件信息
  • 支持 ZIP 文件下载与解压
  • 解压后文件列表展示
  • 多种类型文件预览(图片、文档等)
  • 分页加载列表数据

核心代码实现

页面结构(Template)

<template><view class="contractClass"><!-- 滚动列表区域 --><scroll-view scroll-y class="scrollClass" @scrolltolower="handleToLower"><view class="contentClass"><!-- 文件列表项 --><view class="contentItemClass" v-for="(item,index) in bookList" :key="index"><view class="headClass">{{ item.state_text }}</view><van-divider /><!-- 操作按钮区 --><view class="buttonClass"><view class="downloadClass" @click="downloadFile(item)">下载文件并解压</view></view></view></view></scroll-view><!-- 解压文件列表弹窗 --><van-popup :show="fileShow" round position="bottom"><view class="fileHeaderClass"><view></view><view>解压文件列表</view><uni-icons type="closeempty" @click="closeFn"></uni-icons></view><scroll-view scroll-y class="filesListClass"><view v-for="(item , index) in files" :key="index" class="fileItemClass" @click="previewFn(item)">{{item}}</view></scroll-view></van-popup></view>
</template>

逻辑处理(Script)

<script>export default {data() {return {// 分页数据pageData: {page: 1,pageSize: 10,total: 0},// 文件列表数据bookList: [],// 弹窗显示控制fileShow: false,// 文件系统管理器FileSystemManager: '',// 支持预览的文档类型fileTypeArr: ['doc', 'docx', 'xls', 'xlsx', 'ppt', 'pptx', 'pdf'],// 解压后的文件列表files: [],// 当前操作的文件信息fileObj: {fileName: ''},}},onShow() {// 页面显示时获取列表数据this.getList();},methods: {/*** 预览文件* @param {string} item - 文件名*/previewFn(item) {// 获取文件类型const fileType = this.onchangecb(item);// 构建文件完整路径const fullPath = `${wx.env.USER_DATA_PATH}/extracted/${this.fileObj.fileName}/${item}`;// 图片类型直接预览if (this.isImageFile(item)) {this.previewMediaFn(fullPath);} // 支持的文档类型直接打开else if (this.fileTypeArr.some(type => type === fileType)) {this.openDocumentFn(fullPath);} // 处理目录情况else {this.FileSystemManager.stat({path: fullPath,success: (statRes) => {if (statRes.stats.isDirectory()) {// 如果是目录,读取目录下的文件this.FileSystemManager.readdir({dirPath: fullPath,success: (readRes) => {if (readRes.files && readRes.files.length > 0) {// 递归处理目录下的第一个文件const firstFile = readRes.files[0];this.previewFn(`${item}/${firstFile}`);} else {uni.showToast({title: this.$t('invoicePages.dirEmpty'),icon: 'none',duration: 2000});}},fail: () => {uni.showToast({title: this.$t('invoicePages.nosee'),icon: 'none',duration: 2000});}});} else {// 不支持的文件类型uni.showToast({title: this.$t('invoicePages.nosee'),icon: 'none',duration: 2000});}},fail: () => {uni.showToast({title: this.$t('invoicePages.fileNotFound'),icon: 'none',duration: 2000});}});}},/*** 关闭文件列表弹窗*/closeFn() {this.fileShow = false;this.removeSavedFileFn();this.fileObj.fileName = '';},/*** 获取文件列表数据* @param {string} e - 区分是否是分页加载*/async getList(e) {const data = {};const res = await this.userService.getBusinessList(data);if (res.code === 1) {// 分页加载时合并数据,否则直接替换if (e === 'paging') {this.bookList = [...this.bookList, ...res.data.data];} else {this.bookList = res.data.data;}this.pageData.total = res.data.total || 0;}},/*** 处理滚动到底部事件(分页加载)*/handleToLower() {let paginationTotal = 0;// 计算总页数if (this.pageData.total % 10 === 0) {paginationTotal = Math.floor(this.total / 10)} else {paginationTotal = Math.ceil(this.total / 10)};// 如果还有下一页,加载更多数据if (this.pageData.page < paginationTotal) {this.pageData.page = this.pageData.page + 1;this.getList('paging');}},/*** 获取文件类型* @param {string} e - 文件名* @returns {string} 文件扩展名*/onchangecb(e) {const index = e.lastIndexOf(".");const ext = e.substr(index + 1);return ext;},/*** 判断是否为图片文件* @param {string} filename - 文件名* @returns {boolean} 是否为图片*/isImageFile(filename) {const imageExtensions = ['jpg', 'jpeg', 'png', 'gif', 'bmp', 'svg'];const extension = filename.split('.').pop().toLowerCase();return imageExtensions.includes(extension);},/*** 下载文件* @param {object} item - 文件信息对象*/downloadFile(item) {const that = this;const fileType = this.onchangecb(item.attachment);// 处理ZIP文件if (fileType == 'zip') {this.FileSystemManager = uni.getFileSystemManager();uni.showLoading({title: "加载中...",mask: false});// 下载ZIP文件uni.downloadFile({url: item.attachment,success: res => {// 下载成功后解压that.unzipHandler(res.tempFilePath);},fail: res => {uni.hideLoading();},})} // 处理文档类型else if (this.fileTypeArr.some(type => type == fileType)) {uni.downloadFile({url: item.attachment,success: (res) => {that.openDocumentFn(res.tempFilePath);},});} // 处理图片类型else if(this.isImageFile(item)){uni.downloadFile({url: item.attachment,success: (res) => {that.previewMediaFn(res.tempFilePath);},});} // 不支持的文件类型else {wx.showToast({title: this.$t('invoicePages.nosee'),icon: 'none',duration: 2000,mask: true,});}},/*** 解压文件* @param {string} bookZipPath - ZIP文件路径*/unzipHandler(bookZipPath) {console.log('解压文件')let { FileSystemManager } = this;let that = this;FileSystemManager.unzip({zipFilePath: bookZipPath,targetPath: `${wx.env.USER_DATA_PATH}/extracted`, // 解压目标路径success(res) {// 解压成功后获取文件列表that.lookFileListFn();},})},/*** 获取解压后的文件列表*/lookFileListFn() {let { FileSystemManager } = this;let that = this;FileSystemManager.readdir({dirPath: `${wx.env.USER_DATA_PATH}/extracted`,success(res) {// 记录文件夹名称that.fileObj.fileName = res.files[0];// 获取文件夹内文件列表that.lookFileListFn1();},fail(err) {// 处理错误}})},/*** 获取指定文件夹内的文件列表*/lookFileListFn1() {let { FileSystemManager } = this;let that = this;FileSystemManager.readdir({dirPath: `${wx.env.USER_DATA_PATH}/extracted/${that.fileObj.fileName}`,success(res) {// 保存文件列表并显示弹窗that.files = res.files;that.fileShow = true;uni.hideLoading();},fail(err) {// 处理错误}})},/*** 打开文档* @param {string} attachment - 文件路径*/openDocumentFn(attachment) {uni.openDocument({filePath: attachment,showMenu: true, // 显示菜单success(res) {// 打开成功},fail(err) {// 打开失败}})},/*** 预览图片* @param {string} imagePath - 图片路径*/previewMediaFn(imagePath) {uni.previewMedia({sources:[{url: imagePath,type:'image',}],showShareButton: true, // 显示分享按钮success(res){// 预览成功},fail(err){// 预览失败}})},}}
</script>

样式设计(Style)

<style lang="less" scoped>.contractClass {width: 750rpx;height: 100vh;background-color: #F5F7FB;.scrollClass {width: 100%;height: 100%;.contentClass {padding: 0rpx 40rpx 50px 40rpx;.contentItemClass{background-color: #fff;border-radius: 13rpx;padding: 30rpx;margin-top: 40rpx;.headClass{font-weight: bold;font-size: 29rpx;color: #333333;}.buttonClass{margin-top: 40rpx;display: flex;justify-content: flex-end;align-items: center;.downloadClass{height: 60rpx;background-color: #1B7AFE;color: #fff;border-radius: 30rpx;display: flex;justify-content: center;align-items: center;font-weight: 400;font-size: 29rpx;min-width: 180rpx;}}}}}/* 弹窗样式 */.fileHeaderClass {padding: 24rpx 24rpx 0 24rpx;display: flex;justify-content: space-between;align-items: center;font-size: 36rpx;font-weight: bold;}.filesListClass {padding: 0 24rpx;height: 400rpx;.fileItemClass {color: #2875DA;margin-top: 20rpx;text-decoration: underline;}}}
</style>

核心功能解析

1. 文件下载与解压流程

  1. 用户点击下载按钮触发downloadFile方法
  2. 根据文件类型进行不同处理:
    • ZIP 文件:下载后调用unzipHandler进行解压
    • 文档文件:直接下载并调用openDocumentFn打开
    • 图片文件:下载后调用previewMediaFn预览
  3. 解压处理:
    • 使用FileSystemManager.unzip进行解压
    • 解压路径使用小程序本地存储路径wx.env.USER_DATA_PATH
    • 解压完成后读取文件列表并显示在弹窗中

2. 文件预览机制

系统支持多种类型文件预览,主要通过以下方法实现:

  • previewMediaFn:用于预览图片,支持常见图片格式
  • openDocumentFn:用于打开文档,支持 doc、docx、xls、xlsx、ppt、pptx、pdf 等格式
    - showMenu: true, 显示分享菜单
  • 递归处理:对于解压后包含文件夹的情况,通过递归方式查找可预览的文件
    - showShareButton: true,, 显示分享菜单

3. 分页加载实现

通过scroll-view的scrolltolower事件实现分页加载:

  • 初始加载第一页数据
  • 滚动到底部时触发handleToLower方法
  • 计算总页数与当前页数,判断是否还有更多数据
  • 有更多数据则加载下一页并合并到现有列表

注意事项

  1. 文件路径处理:小程序中文件操作需使用wx.env.USER_DATA_PATH作为基础路径
  2. 权限问题:文件系统操作需要相应的权限,部分操作在不同平台可能有差异
  3. 错误处理:需考虑文件下载失败、解压失败、文件不存在等异常情况
  4. 性能优化:大文件处理可能影响性能,建议添加加载提示并优化用户体验

通过以上实现,我们可以构建一个功能完善的文件管理页面,满足用户下载、解压和预览多种类型文件的需求。
在这里插入图片描述

http://www.dtcms.com/a/297732.html

相关文章:

  • nacos安装
  • SpringBoot配置多数据源多数据库
  • Androidstudio 上传当前module 或本地jar包到maven服务器。
  • 线性代数 上
  • Java 大视界 -- 基于 Java 的大数据分布式存储在工业互联网数据管理与边缘计算协同中的创新实践(364)
  • 从入门到进阶:JavaScript 学习之路与实战技巧
  • Nginx 安装与 HTTPS 配置指南:使用 OpenSSL 搭建安全 Web 服务器
  • Django集成Swagger全指南:两种实现方案详解
  • 探索 MyBatis-Plus
  • 智慧灯杆:不止于照明,塔能科技的城市感知网络野心
  • 解码3D格式转换
  • 多智能体(Multi-agent)策略模式:思维链CoT和ReAct
  • 万字解析Redission ---深入理解Redission上锁过程
  • 百度蜘蛛池解析机制:原创
  • ElementPlus:ElMessageBox增加type
  • iOS 加固工具实战解析,主流平台审核机制与工具应对策略
  • ESB 在零售,物流,制造,保险,医疗行业的应用方式
  • 【Linux/Ubuntu】VIM指令大全
  • Adv. Energy Mater.:焦耳热2分钟制造自支撑磷化物全解水电极
  • 基坑渗压数据不准?选对渗压计能实现自动化精准监测吗?
  • 戴尔电脑 Linux 安装与配置指南_导入mysql共享文件夹
  • 如何制定和落实ITIL 4服务请求的标准化与自动化策略
  • c# openxml 打开加密 的word读取内容
  • (笔记)U-boot 2012.10 armv7启动汇编解析
  • C++STL系列之unordered_set和unordered_map
  • gig-gitignore工具实战开发(四):使用ai辅助生成gitignore
  • 开讲啦|MBSE公开课:第二集 MBSE远景设想
  • cocos creator 3.8.6 websocke的一直报错WebSocket is not a constructor
  • Logstash 多表增量同步 MySQL 到 Elasticsearch:支持逻辑删除与热加载,Docker 快速部署实战
  • vue项目创建流程