vue3 文件分片上传

file分片上传 方法一

bash 复制代码
<template>
  <input type="file" @change="handleFileChange" />
</template>

<script setup>
import { ref } from 'vue';
import axios from 'axios';

const handleFileChange = async (event) => {
  const file = event.target.files[0];
  if (!file) return;
  const chunkSize = 1 * 1024 * 1024; // 每个分片的大小,这里以1MB为例
  const chunkCount = Math.ceil(file.size / chunkSize);
  for (let i = 0; i < chunkCount; i++) {
    const chunk = file.slice(i * chunkSize, (i + 1) * chunkSize);
    const formData = new FormData();
    formData.append('file', chunk);
    // 你可能还需要其他参数,比如文件名、分片总数等
    formData.append('传参', i + 1); //...
    
    try {
      const response = await axios.post('http://192.168.1.45:8086/pic/upload1', formData, {
        headers: {
          'Content-Type': 'multipart/form-data',
        },
        // 其他配置,如上传进度处理等
      });
      console.log(response.data);
    } catch (error) {
      console.error(error);
    }
  }
};
</script>

file分片上传 方法二

bash 复制代码
<template>
  <div>
    <input type="file" @change="onFileSelected" />
    <button v-if="file && !isUploading" @click="startUpload">开始上传</button>
    <button v-if="isUploading" @click="pauseUpload">暂停上传</button>
    <button v-if="isUploading" @click="resumeUpload">继续上传</button>
    <p>已上传分片: {{ uploadedChunks }} / {{ totalChunks }}</p>
    <progress :value="uploadedChunks" :max="totalChunks"></progress>
  </div>
</template>
<script setup>
import { ref, onMounted, onBeforeUnmount } from 'vue';

const file = ref(null);
const isUploading = ref(false);
const uploadedChunks = ref(0);
const totalChunks = ref(0);

const chunkSize = 10 * 1024 * 1024; // 分片大小:10MB
let worker = null;
let uploadQueue = [];
let currentChunkIndex = 0;

function onFileSelected(event) {
  file.value = event.target.files[0];
  if (file.value) {
    totalChunks.value = Math.ceil(file.value.size / chunkSize);
  }
}

async function startUpload() {
  isUploading.value = true;
  worker = new Worker('file-slicer-worker.js');
  worker.postMessage({ file: file.value, chunkSize });
  worker.onmessage = ({ data }) => {
    if (data.type === 'slice') {
      uploadQueue.push(data.chunk);
      uploadNextChunk();
    }
  };
}

function pauseUpload() {
  isUploading.value = false;
}

function resumeUpload() {
  isUploading.value = true;
  uploadNextChunk();
}

async function uploadNextChunk() {
  if (!isUploading.value || currentChunkIndex >= totalChunks.value) return;

  const chunk = uploadQueue.shift();
  await uploadChunk(chunk, currentChunkIndex++);
  uploadedChunks.value = currentChunkIndex;
  if (currentChunkIndex < totalChunks.value) {
    uploadNextChunk();
  } else {
    // 全部上传完毕,清理资源
    worker.terminate();
    worker = null;
    uploadQueue = [];
    isUploading.value = false;
    alert('文件上传完成!');
  }
}

async function uploadChunk(chunk, index) {
  const formData = new FormData();
  formData.append('file', new Blob([chunk]), `file_part_${index}`);
  try {
    const response = await fetch('/api/upload-chunk', {
      method: 'POST',
      body: formData,
    });
    if (!response.ok) {
      throw new Error(`Failed to upload chunk ${index}: ${response.status}`);
    }
  } catch (error) {
    console.error('Error uploading chunk:', error);
    // 处理错误,可能需要重新放入队列或提示用户
  }
}

onMounted(() => {
  // 在组件挂载时注册worker相关事件
});

onBeforeUnmount(() => {
  // 在组件卸载时清理worker资源
  if (worker) {
    worker.terminate();
  }
});


</script>

base 64 分片上传文件
```bash
<template>
  <div>

    <input type="file" @change="onFileSelected" />
    <button v-if="file && !isUploading" @click="startUpload">开始上传</button>
    <button v-if="isUploading" @click="pauseUpload">暂停上传</button>
    <button v-if="isUploading" @click="resumeUpload">继续上传</button>
    <p>已上传分片: {{ uploadedChunks }} / {{ totalChunks }}</p>
    <progress :value="uploadedChunks" :max="totalChunks"></progress>
  </div>
</template>

<script setup>
const file = ref(null);
const isUploading = ref(false);
const uploadedChunks = ref(0);
const totalChunks = ref(0);

const chunkSize = 10 * 1024 * 1024; // 分片大小:1MB
let currentChunkIndex = 0;

function onFileSelected(event) {
  file.value = event.target.files[0];
  if (file.value) {
    totalChunks.value = Math.ceil(file.value.size / chunkSize);
  }
}

async function startUpload() {
  isUploading.value = true;
  await readAndUploadFileInChunks(file.value, chunkSize);
  isUploading.value = false;
  alert('文件上传完成!');
}

function pauseUpload() {
  isUploading.value = false;
}

function resumeUpload() {
  isUploading.value = true;
  // 实现暂停/继续逻辑,这里假设简单地重新开始上传
  startUpload();
}

async function readAndUploadFileInChunks(file, chunkSize) {
  const fileReader = new FileReader();
  let offset = 0;

  while (offset < file.size) {
    const slice = file.slice(offset, offset + chunkSize);
    fileReader.readAsDataURL(slice); // 使用readAsDataURL读取Base64编码

    await new Promise((resolve) => {
      fileReader.onload = () => {
        const base64Data = fileReader.result;
        uploadBase64Chunk(base64Data, currentChunkIndex++);
        resolve();
      };
    });

    offset += chunkSize;
  }
}

async function uploadBase64Chunk(base64Data, index) {
  try {
    const response = await fetch('/api/upload-base64-chunk', {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({ base64Data, index }),
    });
    if (!response.ok) {
      throw new Error(`Failed to upload chunk ${index}: ${response.status}`);
    }
    uploadedChunks.value = index + 1;
  } catch (error) {
    console.error('Error uploading chunk:', error);
    // 处理错误,可能需要重新上传或提示用户
  }
}

onMounted(() => {
  // 在组件挂载时注册相关事件
});

onBeforeUnmount(() => {
  // 在组件卸载时清理资源
});


</script>
相关推荐
API技术员3 分钟前
item_get_app - 根据ID取商品详情原数据H5数据接口实战解析
javascript
八哥程序员4 分钟前
Chrome DevTools 详解系列之 Elements面板
javascript·浏览器
coderHing[专注前端]8 分钟前
告别 try/catch 地狱:用三元组重新定义 JavaScript 错误处理
开发语言·前端·javascript·react.js·前端框架·ecmascript
UIUV25 分钟前
JavaScript中this指向机制与异步回调解决方案详解
前端·javascript·代码规范
momo10025 分钟前
IndexedDB 实战:封装一个通用工具类,搞定所有本地存储需求
前端·javascript
liuniansilence25 分钟前
🚀 高并发场景下的救星:BullMQ如何实现智能流量削峰填谷
前端·分布式·消息队列
再花25 分钟前
在Angular中实现基于nz-calendar的日历甘特图
前端·angular.js
San3031 分钟前
从零到一:彻底搞定面试高频算法——“列表转树”与“爬楼梯”全解析
javascript·算法·面试
GISer_Jing37 分钟前
今天看了京东零售JDS的保温直播,秋招,好像真的结束了,接下来就是论文+工作了!!!加油干论文,学&分享技术
前端·零售
Mapmost1 小时前
【高斯泼溅】如何将“歪头”的3DGS模型精准“钉”在地图上,杜绝后续误差?
前端