vue-simple-uploader增加計算md5狀態(tài)

一、概述

vue-simple-uploader中只有5種狀態(tài),分別是waiting(等待)、paused(暫停)、uploading(上傳中)、success(上傳成功)、error(上傳失敗),在進(jìn)行實(shí)現(xiàn)斷點(diǎn)續(xù)傳及秒傳時,假如要進(jìn)行文件md5計算,此時的狀態(tài)實(shí)際上是暫停狀態(tài),計算md5時,顯示狀態(tài)的文本是"暫停",我需要在計算md5時,顯示狀態(tài)的文本是"計算MD5",這需要在waiting狀態(tài)和paused狀態(tài)之間新增一個計算md5的狀態(tài),比如cmd5(計算MD5),這就需要修改vue-simple-uploader的源碼來實(shí)現(xiàn)。
vue-simple-uploader下載地址:https://gitee.com/tojinhai/vue-uploader.git
我這里下載的是vue-simple-uploader-v1.0.1

二、魔改vue-simple-uploader

2.1 uploader.vue中新增cmd5狀態(tài)

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

2.2 file.vue中新增cmd5狀態(tài)

  • 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屬性的函數(shù)中添加cmd5狀態(tài)
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 安裝依賴

運(yùn)行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:

執(zhí)行解決

npm install --force

3.2 打包

npm run build

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

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

四、應(yīng)用

4.1 替換其他項(xiàng)目中依賴vue-simple-uploader下的dist文件

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

4.2 刪除緩存

如果項(xiàng)目是vite打包的,需要刪除node_modules/.vite目錄,然后執(zhí)行npm run dev運(yùn)行項(xiàng)目

4.3 項(xiàng)目中應(yīng)用cmd5

  • 狀態(tài)文本提示中新增cmd5
const statusTextMap = reactive({
  success: "上傳成功",
  error: "上傳失敗",
  uploading: "上傳中",
  paused: "暫停",
  waiting: "等待上傳",
  cmd5: "計算MD5",//新增的cmd5狀態(tài)
});
  • 計算md5時設(shè)置file.cmd5=true,計算完成后設(shè)置file.cmd5=false
/**
* 計算md5,實(shí)現(xiàn)斷點(diǎn)續(xù)傳及秒傳
* @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; //文件狀態(tài)為“計算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狀態(tài)
     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

但是現(xiàn)在又出現(xiàn)一個問題,上傳進(jìn)度計算有問題,如圖


20241030152341.png

查看vue-simple-uploader源碼,發(fā)現(xiàn)是加入cmd5狀態(tài)后,計算進(jìn)度有問題,使用一個變量來替換進(jìn)度即可,然后重新打包替換文件就行。

# 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時的進(jìn)度

  • 修改file.vue文件,props中增加一計算md5的變量,然后在uploader-file-status下顯示md5的進(jìn)度
export default {
  name: COMPONENT_NAME,
  props: {
    file: {
      type: Object,
      default() {
        return {};
      },
    },
    list: {
      type: Boolean,
      default: false,
    },
    //新增md5進(jìn)度
    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>
  • 父組件調(diào)用修改
<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>
//定義一個數(shù)組接收進(jìn)度變量
const cmd5Progress = reactive([]);

/**
 * 計算md5,實(shí)現(xiàn)斷點(diǎn)續(xù)傳及秒傳
 * @param file
 */
function computeMD5(file) {
  file.pause();
  file.cmd5 = true; //文件狀態(tài)為“計算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狀態(tài)
      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進(jìn)度,動態(tài)賦值
    cmd5Progress[file.id] = Math.floor((currentChunk / chunks) * 100);
    console.log(cmd5Progress[file.id]);
  }
}

結(jié)果:


20241104104426.png

六、參考資料

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

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

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容