在微信小程序開發中,文件處理是常見需求,尤其是涉及合同、文檔等場景。本文將通過一個實際案例,詳細講解如何實現文件的下載、解壓、列表展示及預覽功能。
功能概述
該頁面主要實現了以下核心功能:
- 列表展示可下載的文件信息
- 支持 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. 文件下載與解壓流程
- 用戶點擊下載按鈕觸發downloadFile方法
- 根據文件類型進行不同處理:
- ZIP 文件:下載后調用unzipHandler進行解壓
- 文檔文件:直接下載并調用openDocumentFn打開
- 圖片文件:下載后調用previewMediaFn預覽
- 解壓處理:
- 使用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方法
- 計算總頁數與當前頁數,判斷是否還有更多數據
- 有更多數據則加載下一頁并合并到現有列表
注意事項
- 文件路徑處理:小程序中文件操作需使用wx.env.USER_DATA_PATH作為基礎路徑
- 權限問題:文件系統操作需要相應的權限,部分操作在不同平臺可能有差異
- 錯誤處理:需考慮文件下載失敗、解壓失敗、文件不存在等異常情況
- 性能優化:大文件處理可能影響性能,建議添加加載提示并優化用戶體驗
通過以上實現,我們可以構建一個功能完善的文件管理頁面,滿足用戶下載、解壓和預覽多種類型文件的需求。