vue-simple-uploader增加计算md5状态

一、概述

vue-simple-uploader中只有5种状态,分别是waiting(等待)、paused(暂停)、uploading(上传中)、success(上传成功)、error(上传失败),在进行实现断点续传及秒传时,假如要进行文件md5计算,此时的状态实际上是暂停状态,计算md5时,显示状态的文本是"暂停",我需要在计算md5时,显示状态的文本是"计算MD5",这需要在waiting状态和paused状态之间新增一个计算md5的状态,比如cmd5(计算MD5),这就需要修改vue-simple-uploader的源码来实现。
vue-simple-uploader下载地址:https://gitee.com/tojinhai/vue-uploader.git
我这里下载的是vue-simple-uploader-v1.0.1

二、魔改vue-simple-uploader

2.1 uploader.vue中新增cmd5状态

fileStatusText: {
    type: [Object, Function],
    default () {
      return {
        success: 'success',
        error: 'error',
        uploading: 'uploading',
        paused: 'paused',
        waiting: 'waiting',
        cmd5:'cmd5'
      }
    }
  },

2.2 file.vue中新增cmd5状态

  • slot中新增cmd5属性
<slot
     :file="file"
     :list="list"
     :status="status"
     :paused="paused"
     :error="error"
     :response="response"
     :average-speed="averageSpeed"
     :formated-average-speed="formatedAverageSpeed"
     :current-speed="currentSpeed"
     :is-complete="isComplete"
     :is-uploading="isUploading"
     :size="size"
     :cmd5="cmd5" //增加cmd5属性
     :formated-size="formatedSize"
     :uploaded-size="uploadedSize"
     :progress="progress"
     :progress-style="progressStyle"
     :progressing-class="progressingClass"
     :time-remaining="timeRemaining"
     :formated-time-remaining="formatedTimeRemaining"
     :type="type"
     :extension="extension"
     :file-category="fileCategory"
     >
     ...
  • 初始化cmd5值
setup (props) {
    const cmd5=ref(false)
    ...
}
  • 计算status属性的函数中添加cmd5状态
const status = computed(() => {
     let isError = error
     if (isComplete.value) {
       return 'success'
     } else if (isError.value) {
       return 'error'
     } else if (isUploading.value) {
       return 'uploading'
     } else if (cmd5.value) {//需要增加在paused前面
       return 'cmd5'
     } else if (paused.value) {
       return 'paused'
     } else {
       return 'waiting'
     }
   })
  • actionCheck中增加cmd5
 const actionCheck = () => {
      paused.value = props.file.paused;
      error.value = props.file.error;
      isUploading.value = props.file.isUploading();
      cmd5.value=props.file.cmd5;
    };
  • onMount中增加cmd5
 onMounted(() => {
      paused.value = props.file["paused"];
      cmd5.value = props.file["cmd5"];
     ...
  • 最后的return中增加cmd5
    return {
      response,
      paused,
      error,
      cmd5,
      ...

三、打包

3.1 安装依赖

运行npm install报错

PS E:\work\vue\vue\vue-uploader-v1.0.1> npm install
npm error code ERESOLVE
npm error ERESOLVE could not resolve
npm error
npm error While resolving: url-loader@0.5.9
npm error Found: webpack@3.12.0
npm error node_modules/webpack
npm error   peer webpack@"2 || 3" from babel-loader@7.1.2
npm error   node_modules/babel-loader
npm error     dev babel-loader@"^7.1.1" from the root project
npm error   peer webpack@"1 || ^2 || ^2.1.0-beta || ^2.2.0-rc || ^3" from html-webpack-plugin@2.30.1
npm error   node_modules/html-webpack-plugin
npm error     dev html-webpack-plugin@"^2.28.0" from the root project
npm error
npm error Could not resolve dependency:
npm error peer file-loader@"*" from url-loader@0.5.9
npm error node_modules/url-loader
npm error   dev url-loader@"^0.5.8" from the root project
npm error
npm error Conflicting peer dependency: webpack@5.95.0
npm error node_modules/webpack
npm error   peer webpack@"^4.0.0 || ^5.0.0" from file-loader@6.2.0
npm error   node_modules/file-loader
npm error     peer file-loader@"*" from url-loader@0.5.9
npm error     node_modules/url-loader
npm error       dev url-loader@"^0.5.8" from the root project
npm error
npm error Fix the upstream dependency conflict, or retry
npm error to accept an incorrect (and potentially broken) dependency resolution.
npm error
npm error
npm error For a full report see:

执行解决

npm install --force

3.2 打包

npm run build

打包成功后会在vue-simple-uploader/dist下生成三个文件

style.css
vue-simple-uploader.es.js
vue-simple-uploader.umd.js

四、应用

4.1 替换其他项目中依赖vue-simple-uploader下的dist文件

将打包后的文件替换到node_modules/vue-simple-uploader/dist下

4.2 删除缓存

如果项目是vite打包的,需要删除node_modules/.vite目录,然后执行npm run dev运行项目

4.3 项目中应用cmd5

  • 状态文本提示中新增cmd5
const statusTextMap = reactive({
  success: "上传成功",
  error: "上传失败",
  uploading: "上传中",
  paused: "暂停",
  waiting: "等待上传",
  cmd5: "计算MD5",//新增的cmd5状态
});
  • 计算md5时设置file.cmd5=true,计算完成后设置file.cmd5=false
/**
* 计算md5,实现断点续传及秒传
* @param file
*/
function computeMD5(file) {
 file.pause();
 //单个文件的大小限制2G
 let fileSizeLimit = 2 * 1024 * 1024 * 1024;
 console.log("文件大小:" + file.size);
 console.log("限制大小:" + fileSizeLimit);
 if (file.size > fileSizeLimit) {
   file.cancel();
   ElMessage.error("限制上传文件大小不能超过2G");
   return;
 }
 let fileReader = new FileReader();
 let time = new Date().getTime();
 let blobSlice =
   File.prototype.slice ||
   File.prototype.mozSlice ||
   File.prototype.webkitSlice;
 let currentChunk = 0;
 const chunkSize = 10 * 1024 * 1000;
 let chunks = Math.ceil(file.size / chunkSize);
 let spark = new SparkMD5.ArrayBuffer();
 //由于计算整个文件的Md5太慢,因此采用只计算第1块文件的md5的方式
 // let chunkNumberMD5 = 1;
 file.cmd5 = true; //文件状态为“计算md5...”

 loadNext();

 fileReader.onload = (e) => {
   spark.append(e.target.result);
   if (currentChunk < chunks) {
     loadNext();
   } else {
     let md5 = spark.end();
     file.uniqueIdentifier = md5;
     file.cmd5 = false; //取消计算md5状态
     file.resume();
     console.log(
       `MD5计算完毕:${file.name} \nMD5:${md5} \n分片:${chunks} 大小:${
         file.size
       } 用时:${new Date().getTime() - time} ms`
     );
   }
 };

 fileReader.onerror = function () {
   error(`文件${file.name}读取出错,请检查该文件`);
   file.cancel();
 };

 function loadNext() {
   let start = currentChunk * chunkSize;
   let end = start + chunkSize >= file.size ? file.size : start + chunkSize;

   fileReader.readAsArrayBuffer(blobSlice.call(file.file, start, end));
   currentChunk++;
   console.log("计算第" + currentChunk + "块");
 }
}
20241030152203.png

但是现在又出现一个问题,上传进度计算有问题,如图


20241030152341.png

查看vue-simple-uploader源码,发现是加入cmd5状态后,计算进度有问题,使用一个变量来替换进度即可,然后重新打包替换文件就行。

# file.vue
  const progressStyle = computed(() => {
      let progressValue = Math.floor(progress.value * 100);
      //progress.value = Math.floor(progress.value * 100);
      //const style = `translateX(${Math.floor(progress.value - 100)}%)`;
      const style = `translateX(${Math.floor(progressValue - 100)}%)`;
      return {
        progress: `${progressValue}%`,
        //progress: `${progress.value}%`,
        webkitTransform: style,
        mozTransform: style,
        msTransform: style,
        transform: style,
      };
    });

五、其他

5.1 如何增加计算MD5时的进度

  • 修改file.vue文件,props中增加一计算md5的变量,然后在uploader-file-status下显示md5的进度
export default {
  name: COMPONENT_NAME,
  props: {
    file: {
      type: Object,
      default() {
        return {};
      },
    },
    list: {
      type: Boolean,
      default: false,
    },
    //新增md5进度
    cmd5Progress: {
      type: Number,
      default: 0,
    },
  },

...
 <div class="uploader-file-status">
  <span v-show="status !== 'uploading' && status !== 'cmd5'">{{
    statusText
  }}</span>
  <span v-show="status !== 'uploading' && status === 'cmd5'"
>{{ statusText }}{{ cmd5Progress }}%</span
>
  <span v-show="status === 'uploading'">
    <span>{{ progressStyle.progress }}&nbsp;</span>
    <em>{{ formatedAverageSpeed }}&nbsp;</em>
    <i>{{ formatedTimeRemaining }}</i>
  </span>
</div>
  • 父组件调用修改
<template>
 <div>
   <!-- 上传器 -->
   <uploader
     ref="uploaderRef"
     :options="options"
     :autoStart="false"
     :file-status-text="fileStatusText"
     class="uploader-ui"
     @file-added="onFileAdded"
     @file-success="onFileSuccess"
     @file-progress="onFileProgress"
     @file-error="onFileError"
   >
     <uploader-unsupport></uploader-unsupport>
     <uploader-drop>
       <div>
         <uploader-btn ref="uploadBtn" :attrs="attrs"
           ><el-icon><Files /></el-icon> 选择文件</uploader-btn
         >
         <uploader-btn :directory="true"
           ><el-icon><Folder /></el-icon> 选择文件夹</uploader-btn
         >
       </div>
     </uploader-drop>
     <uploader-list>
       <template v-slot:default="props">
         <div class="file-panel">
           <ul class="file-list">
             <li v-for="file in props.fileList" :key="file.id">
               <uploader-file
                 :class="'file_' + file.id"
                 ref="files"
                 :file="file"
                 :cmd5Progress="cmd5Progress[file.id]"
                 :list="true"
               >
               </uploader-file>
             </li>
             <div class="no-file" v-if="!props.fileList.length">
               <!-- <i class="iconfont icon-empty-file"></i> 暂无待上传文件 -->
               <el-empty :image-size="100">
                 <template #description>
                   <p>
                     暂无文件,请先<a class="upload" @click="upload">上传</a>
                   </p>
                 </template>
               </el-empty>
             </div>
           </ul>
         </div>
       </template>
     </uploader-list>
   </uploader>
 </div>
</template>
//定义一个数组接收进度变量
const cmd5Progress = reactive([]);

/**
 * 计算md5,实现断点续传及秒传
 * @param file
 */
function computeMD5(file) {
  file.pause();
  file.cmd5 = true; //文件状态为“计算md5...”
  //单个文件的大小限制2G
  let fileSizeLimit = 2 * 1024 * 1024 * 1024;
  console.log("文件大小:" + file.size);
  console.log("限制大小:" + fileSizeLimit);
  if (file.size > fileSizeLimit) {
    file.cancel();
    ElMessage.error("限制上传文件大小不能超过2G");
    return;
  }

  let fileReader = new FileReader();
  let time = new Date().getTime();
  let blobSlice =
    File.prototype.slice ||
    File.prototype.mozSlice ||
    File.prototype.webkitSlice;
  let currentChunk = 0;
  const chunkSize = 10 * 1024 * 1000;
  let chunks = Math.ceil(file.size / chunkSize);
  let spark = new SparkMD5.ArrayBuffer();
  //由于计算整个文件的Md5太慢,因此采用只计算第1块文件的md5的方式
  // let chunkNumberMD5 = 1;
  loadNext();
  fileReader.onload = (e) => {
    spark.append(e.target.result);
    if (currentChunk < chunks) {
      loadNext();
    } else {
      let md5 = spark.end();
      file.uniqueIdentifier = md5;
      file.cmd5 = false; //取消计算md5状态
      file.resume();
      console.log(
        `MD5计算完毕:${file.name} \nMD5:${md5} \n分片:${chunks} 大小:${
          file.size
        } 用时:${new Date().getTime() - time} ms`
      );
    }
  };

  fileReader.onerror = function () {
    error(`文件${file.name}读取出错,请检查该文件`);
    file.cancel();
  };

  function loadNext() {
    let start = currentChunk * chunkSize;
    let end = start + chunkSize >= file.size ? file.size : start + chunkSize;
    fileReader.readAsArrayBuffer(blobSlice.call(file.file, start, end));
    currentChunk++;
    console.log("计算第" + currentChunk + "块");
    //计算cmd5进度,动态赋值
    cmd5Progress[file.id] = Math.floor((currentChunk / chunks) * 100);
    console.log(cmd5Progress[file.id]);
  }
}

结果:


20241104104426.png

六、参考资料

https://www.shanhubei.com/archives/2079.html

代码:https://gitee.com/hzhh123/vue-uploader.git vue3分支

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,372评论 6 498
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,368评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 162,415评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,157评论 1 292
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,171评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,125评论 1 297
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,028评论 3 417
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,887评论 0 274
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,310评论 1 310
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,533评论 2 332
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,690评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,411评论 5 343
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,004评论 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,659评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,812评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,693评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,577评论 2 353

推荐阅读更多精彩内容