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

Uniapp实现多种文件类型上传

一、前言

在移动端开发中,文件上传是常见的功能需求。本文将通过Uniapp框架,详细讲解如何实现支持多类型文件(图片、视频、文档等)的上传功能,并解决跨平台兼容性问题😄😄😄。


二、技术方案

2.1 核心API

Uniapp提供了以下关键API:

  • uni.chooseFile:文件选择
  • uni.uploadFile:文件上传
  • uni.getFileInfo:获取文件信息

2.2 平台差异处理

平台文件选择方式限制说明
H5<input type="file">依赖浏览器实现
微信小程序wx.chooseMessageFile需配置合法域名
Appplus.io 文件系统需处理本地文件路径

三、完整实现代码

3.1 文件选择器封装

// 多类型文件选择
function chooseFiles(fileType = 'all') {
  return new Promise((resolve, reject) => {
    const extnameMap = {
      image: ['png', 'jpg', 'jpeg'],
      video: ['mp4', 'mov'],
      document: ['pdf', 'doc', 'docx', 'xls']
    };

    uni.chooseFile({
      count: 5, // 最大选择数量
      extension: fileType === 'all' ? [] : extnameMap[fileType],
      success: res => {
        const files = res.tempFiles.map(item => ({
          path: item.path,
          name: item.name,
          size: item.size,
          type: item.type
        }));
        resolve(files);
      },
      fail: err => reject(err)
    });
  });
}

3.2 文件上传核心方法

// 上传文件到服务器
async function uploadFile(file) {
  try {
    const formData = {
      userId: '123',
      fileType: file.type
    };

    const res = await uni.uploadFile({
      url: 'https://api.example.com/upload',
      filePath: file.path,
      name: 'file',
      formData,
      header: {
        'Authorization': 'Bearer token'
      }
    });

    return JSON.parse(res[1].data);
  } catch (error) {
    console.error('上传失败:', error);
    throw error;
  }
}

3.3 进度显示实现

// 带进度上传
function uploadWithProgress(file, onProgress) {
  return new Promise((resolve, reject) => {
    const task = uni.uploadFile({
      url: 'https://api.example.com/upload',
      filePath: file.path,
      name: 'file',
      success: (res) => resolve(JSON.parse(res.data)),
      fail: reject,
      complete: () => task.offProgressUpdate()
    });

    task.onProgressUpdate((res) => {
      onProgress && onProgress({
        progress: res.progress,
        totalBytesSent: res.totalBytesSent,
        totalBytesExpectedToSend: res.totalBytesExpectedToSend
      });
    });
  });
}

四、界面实现示例

<template>
  <view class="upload-container">
    <button @click="chooseFiles">选择文件</button>
    <view class="preview-list">
      <view v-for="(file, index) in files" :key="index" class="file-item">
        <image v-if="file.type.startsWith('image/')" :src="file.path" mode="aspectFit"/>
        <video v-else-if="file.type.startsWith('video/')" :src="file.path"/>
        <view v-else class="document-icon">
          <text>{{ getFileExt(file.name) }}</text>
        </view>
        <progress :percent="file.progress" show-info />
      </view>
    </view>
  </view>
</template>

<style>
/* 文件预览样式 */
.preview-list {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 10px;
  margin-top: 20px;
}

.file-item {
  position: relative;
  width: 100px;
  height: 100px;
  border: 1px dashed #ddd;
}

.document-icon {
  display: flex;
  justify-content: center;
  align-items: center;
  height: 100%;
  background: #f0f0f0;
}
</style>

五、服务端配合建议

5.1 文件接收配置(Node.js示例)

const multer = require('multer');
const storage = multer.diskStorage({
  destination: 'uploads/',
  filename: (req, file, cb) => {
    const ext = path.extname(file.originalname);
    cb(null, `${Date.now()}${ext}`);
  }
});

const upload = multer({
  storage,
  limits: {
    fileSize: 1024 * 1024 * 50 // 50MB
  },
  fileFilter: (req, file, cb) => {
    const allowedTypes = ['image/jpeg', 'image/png', 'video/mp4', 'application/pdf'];
    cb(null, allowedTypes.includes(file.mimetype));
  }
});

router.post('/upload', upload.single('file'), (req, res) => {
  // 处理上传成功逻辑
});

六、注意事项🐛

  1. 文件大小限制:需同时在前端和服务端设置
  2. 格式验证:不能仅依赖前端验证
  3. 安全处理
    • 重命名存储文件
    • 扫描恶意文件
    • 设置访问权限
  4. 性能优化
    • 图片压缩(可使用uni.compressImage)
    • 分片上传大文件
    • 断点续传

相关文章:

  • 缓存之美:Guava Cache 相比于 Caffeine 差在哪里?
  • 文件管理器显示文件的方式是图标还是小图标还是列表需要看ListView_IsIconView宏定义
  • Git 的基本概念和使用方式。
  • 案例分析:安防5G低代码开发网关如何提升城市监控效率
  • 数据库核心-redo、undo
  • 关于ModbusTCP/RTU协议转Ethernet/IP(CIP)协议的方案
  • 【微信小程序 onTabItemTap:精准监听 TabBar 点击事件】
  • 解锁 AI 量化新境界:Qbot 携手 iTick
  • VSCode快捷键整理
  • 【WPF】在System.Drawing.Rectangle中限制鼠标保持在Rectangle中移动?
  • Uniapp组件 Textarea 字数统计和限制
  • DeepSeekR1之四_在RAGFlow中配置DeepSeekR1模型
  • 【春招笔试真题】饿了么2025.03.07-开发岗真题
  • mac 被禁用docker ui后,如何使用lima虚拟机启动docker
  • 贪心算法--
  • C语言练习题--洛谷P生日*****(学会了新的思路)
  • leetcode日记(90)二叉树的锯齿形层序遍历
  • 【已解决】最新 Android Studio(2024.3.1版本)下载安装配置 图文超详细教程 手把手教你 小白
  • 文件操作详解(万字长文)
  • 如何检查电脑的硬盘健康状况?
  • 六大车企一季报:比亚迪近92亿净利稳居第一,多家车企营收下滑
  • 工人日报关注跟着演出去旅游:票根经济新模式兴起,让过路客变过夜客
  • 玉渊谭天丨是自保还是自残?八个恶果透视美国征收100%电影关税
  • 马上评|子宫肌瘤惊现男性患者,如此论文何以一路绿灯?
  • 蓝佛安主持东盟与中日韩财长和央行行长系列会议并举行多场双边会见
  • 市值增22倍,巴菲特30年重仓股盘点