大文件下载、暂停、继续下载

// Vue3 Composition API
import { ref, reactive, onMounted, onUnmounted } from 'vue';
import axios from 'axios';

export default {
  setup() {
    // 状态变量
    const fileUrl = ref(''); // 文件URL
    const currentStart = ref(0); // 当前下载的起始位置(字节)
    const totalSize = ref(0); // 总文件大小(字节)
    const downloadedSize = ref(0); // 已经下载的文件大小(字节)
    const isDownloading = ref(false); // 是否正在下载
    const downloadProgress = ref(0); // 下载进度(百分比)
    const chunks = reactive([]); // 存储已下载的文件分片信息

    // 方法
    const startDownload = async () => {
      isDownloading.value = true;
      try {
        while (currentStart.value < totalSize.value && isDownloading.value) {
          // 设置请求Header中的Range字段
          const end = Math.min(currentStart.value + chunkSize - 1, totalSize.value - 1);
          const config = {
            headers: {
              Range: `bytes=${currentStart.value}-${end}`,
            },
          };

          // 发送带Range头的GET请求
          const response = await axios.get(fileUrl.value, config);

          // 如果成功获取部分数据
          if (response.status === 206) {
            // 存储下载的分片
            chunks.push({ start: currentStart.value, data: response.data });

            // 更新下载位置和已下载大小
            currentStart.value += response.data.byteLength;
            downloadedSize.value += response.data.byteLength;

            // 计算下载进度
            downloadProgress.value = Math.floor((downloadedSize.value / totalSize.value) * 100);

            // 检查是否下载完毕
            if (currentStart.value >= totalSize.value) {
              // 执行文件合并逻辑并结束下载
              mergeAndDownload(chunks);
              isDownloading.value = false;
              return;
            }
          } else {
            console.error('Failed to fetch file chunk');
            break;
          }
        }
      } catch (error) {
        console.error('Error during download:', error);
        isDownloading.value = false;
      }
    };

    const pauseDownload = () => {
      isDownloading.value = false;
    };

    const resumeDownload = async () => {
      // 从上次暂停的地方开始下载
      isDownloading.value = true;
      startDownload();
    };

    // 获取总文件大小
    const fetchTotalFileSize = async () => {
      // 使用HEAD请求获取Content-Length
      const response = await axios.head(fileUrl.value);
      totalSize.value = parseInt(response.headers['content-length'], 10);
    };

    // 合并Blob分片为完整文件并提供下载
    const mergeAndDownload = chunks => {
      const blobParts = chunks.map(chunk => new Blob([chunk.data]));
      const fullBlob = new Blob(blobParts, { type: 'application/octet-stream' });
      const url = URL.createObjectURL(fullBlob);
      const link = document.createElement('a');
      link.href = url;
      link.download = 'filename.ext'; // 替换为实际的文件名
      document.body.appendChild(link);
      link.click();
      setTimeout(() => {
        document.body.removeChild(link);
        URL.revokeObjectURL(url);
      }, 0);
    };

    // 生命周期钩子
    onMounted(async () => {
      // 先获取总文件大小
      await fetchTotalFileSize();
      // 初始化或恢复下载
      if (/* 恢复下载条件 */) {
        resumeDownload();
      }
    });

    onUnmounted(() => {
      // 清理资源(如有必要)
    });

    return {
      startDownload,
      pauseDownload,
      resumeDownload,
      downloadProgress,
    };
  },
};

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

猛男敲代码

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值