zoukankan      html  css  js  c++  java
  • Vue+elelemtUI实现断点续传(前端)

    一、在config->index.js中设置 proxy

    1 devServer: {
    2         proxy: {
    3             '/': {
    4                 target: 'http://127.0.0.1:8888',
    5                 changeOrigin: true
    6             }
    7         }
    8     }

    二、下载并引用相应依赖 (main.js)

      本次demo是利用 Element-ui 配合开发。

      所需依赖(我的版本):

        "element-ui": "^2.13.2",

        "axios": "^0.19.2",

        "spark-md5": "^3.0.1",

        "qs": "^6.9.4",

       如果嫌一个一个下载麻烦,可以把上面内容复制到 package.json 中 “dependencies” ,执行  "npm install" 即可。

      main.js引入所需包:

    1 import ElementUI from 'element-ui';
    2 import 'element-ui/lib/theme-chalk/index.css';
    3 Vue.use(ElementUI);

      App.vue中引入所需包:

      

    1 import { fileParse } from "./assets/utils";
    2 import axios from "axios";
    3 import SparkMD5 from "spark-md5";

    三、HTML部分

      使用Element-UI实现前端样式展示

     1 <template>
     2   <div id="app">
     3     <el-upload drag action :auto-upload="false" :show-file-list="false" :on-change="changeFile">
     4       <i class="el-icon-upload"></i>
     5       <div class="el-upload__text">
     6         将文件拖到此处,或
     7         <em>点击上传</em>
     8       </div>
     9     </el-upload>
    10 
    11     <!-- PROGRESS -->
    12     <div class="progress">
    13       <span>上传进度:{{total|totalText}}%</span>
    14       <el-link type="primary" v-if="total>0 && total<100" @click="handleBtn">{{btn|btnText}}</el-link>
    15     </div>
    16 
    17     <!-- VIDEO -->
    18     <div class="uploadImg" v-if="video">
    19       <video :src="video" controls />
    20     </div>
    21   </div>
    22 </template>

    四、使用 promise 封装 fileParse方法

        promise:promise构造函数是同步执行的,并且是立即执行的函数,promise.then中的函数是异步的。并且promise状态改变后将不会再更改。

        Promise有三个状态:pending(等待)、fulfilled(实现)、rejected(拒绝),其中resolvereject只有第一次执行有效。

      utils.js(对文件转义形式进行封装,根据所传入参数确定封装格式【base64、buffer】)

     1 export function fileParse(file, type = "base64") {
     2     return new Promise(resolve => {
     3         let fileRead = new FileReader();
     4         if (type === "base64") {
     5             fileRead.readAsDataURL(file);
     6         } else if (type === "buffer") {
     7             fileRead.readAsArrayBuffer(file);
     8         }
     9         fileRead.onload = (ev) => {
    10             resolve(ev.target.result);
    11         };
    12     });
    13 };

    五、逻辑流程(前端)

       

      1、利用结合promise封装filepase方法,解析文件为buffer数据

      2、使用sparkMD5生成文件的哈希值,并获取后缀;使用spark.append(buffer)生成哈希值

      3、通过正则获取文件后缀

      4、创建切面默认参数,包括:切片个数、索引值和结束值

      5、通过flie.slice()进行切片

      6、进行遍历上传切片,判断当前索引  >=  切片数组后停止,调用合并文件接口告知服务器进行合并

      

    六、项目整体代码

      1 <script>
      2 import { fileParse } from "./assets/utils";
      3 import axios from "axios";
      4 import SparkMD5 from "spark-md5";
      5 
      6 export default {
      7   name: "App",
      8   data() {
      9     return {
     10       total: 0,
     11       video: null,
     12       btn: false,
     13     };
     14   },
     15   filters: {
     16     btnText(btn) {
     17       return btn ? "继续" : "暂停";
     18     },
     19     totalText(total) {
     20       return total > 100 ? 100 : total;
     21     },
     22   },
     23   methods: {
     24     async changeFile(file) {
     25       if (!file) return;
     26       file = file.raw;
     27 
     28       // 解析为BUFFER数据
     29       // 我们会把文件切片处理:把一个文件分割成为好几个部分(固定数量/固定大小)
     30       // 每一个切片有自己的部分数据和自己的名字
     31       // HASH_1.mp4
     32       // HASH_2.mp4
     33       // ...
     34       let buffer = await fileParse(file, "buffer"),
     35         spark = new SparkMD5.ArrayBuffer(),
     36         hash,
     37         suffix;
     38       spark.append(buffer);
     39       hash = spark.end();
     40       suffix = /.([0-9a-zA-Z]+)$/i.exec(file.name)[1];
     41 
     42       // 创建100个切片
     43       let partList = [],
     44         partsize = file.size / 100,
     45         cur = 0;
     46       for (let i = 0; i < 100; i++) {
     47         let item = {
     48           chunk: file.slice(cur, cur + partsize),
     49           filename: `${hash}_${i}.${suffix}`,
     50         };
     51         cur += partsize;
     52         partList.push(item);
     53       }
     54 
     55       this.partList = partList;
     56       this.hash = hash;
     57       this.sendRequest();
     58     },
     59     async sendRequest() {
     60       // 根据100个切片创造100个请求(集合)
     61       let requestList = [];
     62       this.partList.forEach((item, index) => {
     63         // 每一个函数都是发送一个切片的请求
     64         let fn = () => {
     65           let formData = new FormData();
     66           formData.append("chunk", item.chunk);
     67           formData.append("filename", item.filename);
     68           return axios
     69             .post("/single3", formData, {
     70               headers: { "Content-Type": "multipart/form-data" },
     71             })
     72             .then((result) => {
     73               result = result.data;
     74               if (result.code == 0) {
     75                 this.total += 1;
     76                 // 传完的切片我们把它移除掉
     77                 this.partList.splice(index, 1);
     78               }
     79             });
     80         };
     81         requestList.push(fn);
     82       });
     83 
     84       // 传递:并行(ajax.abort())/串行(基于标志控制不发送)
     85       let i = 0;
     86       let complete = async () => {
     87         let result = await axios.get("/merge", {
     88           params: {
     89             hash: this.hash,
     90           },
     91         });
     92         result = result.data;
     93         if (result.code == 0) {
     94           this.video = result.path;
     95         }
     96       };
     97       let send = async () => {
     98         // 已经中断则不再上传
     99         if (this.abort) return;
    100         if (i >= requestList.length) {
    101           // 都传完了
    102           complete();
    103           return;
    104         }
    105         await requestList[i]();
    106         i++;
    107         send();
    108       };
    109       send();
    110     },
    111     handleBtn() {
    112       if (this.btn) {
    113         //断点续传
    114         this.abort = false;
    115         this.btn = false;
    116         this.sendRequest();
    117         return;
    118       }
    119       //暂停上传
    120       this.btn = true;
    121       this.abort = true;
    122     },
    123   },
    124 };
    125 </script>

      参考资料:https://www.bilibili.com/video/BV18v411v7Xu?t=346

  • 相关阅读:
    计算机网络学习目录
    手把手教你玩微信小程序跳一跳
    (三)python函数式编程
    跟托福说分手
    (二)python高级特性
    BitCoin工作原理
    反向传播的工作原理(深度学习第三章)
    1.22计划
    梯度下降——神经网络如何学习?(深度学习第二章)
    什么是神经网络 (深度学习第一章)?
  • 原文地址:https://www.cnblogs.com/wyd168/p/14545745.html
Copyright © 2011-2022 走看看