上传文件夹

基础实现原理

1. 核心 HTML5 特性
// 关键属性:
<input type="file" webkitdirectory multiple>
  • webkitdirectory: 启用文件夹选择模式(Chrome/Edge)
  • multiple: 允许选择多个文件(自动包含文件夹内所有文件)
  • 注意:Firefox 需使用 mozdirectory,Safari 支持有限
2. **文件数据结构
File 对象包含关键属性:
- name: 文件名(不含路径)
- webkitRelativePath: 相对路径(如 "docs/2024/report.pdf"- size: 文件大小(字节)
- type: MIME 类型

Vue 基础实现

1. 组件模板
<template>
  <div>
    <button @click="triggerUpload">上传文件夹</button>
    <input
      ref="fileInput"
      type="file"
      webkitdirectory
      multiple
      @change="handleUpload"
      style="display: none"
    >
  </div>
</template>
2. 核心逻辑
export default {
  methods: {
    triggerUpload() {
      this.$refs.fileInput.click();
    },
    async handleUpload(e) {
      const files = Array.from(e.target.files);
      
      // 创建 FormData
      const formData = new FormData();
      files.forEach(file => {
        // 参数说明:
        // 1. 'files[]' - 服务器接收的字段名(数组形式)
        // 2. file - File 对象
        // 3. file.webkitRelativePath - 保留目录结构
        formData.append('files[]', file, file.webkitRelativePath);
      });

      try {
        await axios.post('/api/upload', formData, {
          headers: { 'Content-Type': 'multipart/form-data' },
          onUploadProgress: progress => {
            const percent = Math.round((progress.loaded * 100) / progress.total);
            console.log(`进度: ${percent}%`);
          }
        });
        alert('上传成功!');
      } catch (error) {
        console.error('上传失败:', error);
      }
    }
  }
}

常见问题解决方案

1. 浏览器兼容性问题
// 统一处理目录属性
mounted() {
  const input = this.$refs.realInput;
  if ('directory' in input) {
    input.setAttribute('directory', '');
  } else if ('webkitdirectory' in input) {
    input.setAttribute('webkitdirectory', '');
  }
}
2. 文件类型过滤
handleRealChange(e) {
  const files = Array.from(e.target.files).filter(file => {
    const allowedTypes = ['image/jpeg', 'application/pdf'];
    const maxSize = 10 * 1024 * 1024; // 10MB
    
    return allowedTypes.includes(file.type) && file.size <= maxSize;
  });
  
  if (files.length < e.target.files.length) {
    this.$message.warning('包含不支持的文件类型');
  }
  // ...后续处理
}
3. 大文件分片上传
async uploadLargeFile(file) {
  const CHUNK_SIZE = 5 * 1024 * 1024; // 5MB/片
  const totalChunks = Math.ceil(file.size / CHUNK_SIZE);

  for (let i = 0; i < totalChunks; i++) {
    const chunk = file.slice(i * CHUNK_SIZE, (i+1) * CHUNK_SIZE);
    const formData = new FormData();
    
    formData.append('chunk_index', i);
    formData.append('total_chunks', totalChunks);
    formData.append('file_path', file.webkitRelativePath);
    formData.append('chunk', chunk);

    await axios.post('/api/chunk-upload', formData);
  }
  
  // 合并请求
  await axios.post('/api/merge-files', {
    file_path: file.webkitRelativePath,
    total_chunks: totalChunks
  });
}

最佳实践建议

  1. 用户体验优化

    • 添加拖拽上传支持
    <div 
      class="drop-zone"
      @dragover.prevent
      @drop.prevent="handleDrop"
    >
      拖拽文件夹到此区域
    </div>
    
    methods: {
      handleDrop(e) {
        const files = e.dataTransfer.files;
        this.processFiles(files);
      }
    }
    
  2. 安全防护

    • 文件类型白名单验证
    • 扫描文件内容(如防病毒)
    • 设置合理的文件大小限制
  3. 进度显示增强

<el-progress 
  :percentage="uploadPercent" 
  :status="uploadStatus"
  :stroke-width="16"
></el-progress>

// 数据项
data() {
  return {
    uploadPercent: 0,
    uploadStatus: 'success' // 状态:success/exception
  }
}

浏览器支持列表

浏览器支持情况备注
Chrome 78+✅ 完整支持最佳实践浏览器
Edge 79+✅ 完整支持
Firefox 50+⚠️ 需使用 mozdirectory需要额外兼容代码
Safari 11+⚠️ 部分支持可能丢失目录结构
移动端浏览器❌ 不支持需改用 ZIP 上传方案

本总结涵盖了从基础实现到企业级优化的完整知识体系,建议根据实际需求选择合适方案,开发时特别注意浏览器兼容性和服务器安全防护。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值