Vue+elelemtUI实现断点续传(前端)
⼀、在config->index.js中设置 proxy
1 devServer: {
2        proxy: {
3            '/': {
4                target: '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(拒绝),其中resolve和reject只有第⼀次执⾏有效。
  utils.js(对⽂件转义形式进⾏封装,根据所传⼊参数确定封装格式【base64、buffer】)
1 export function fileParse(file, type = "base64") {
2return new Promise(resolve => {
正则匹配哈希值3        let fileRead = new FileReader();
4if (type === "base64") {
5            adAsDataURL(file);
6        } else if (type === "buffer") {
7            adAsArrayBuffer(file);
8        }
9        load = (ev) => {
10            resolve(sult);
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 SparkMD
5 from "spark-md5";
5
6 export default {
7  name: "App",
8  data() {
9return {
10      total: 0,
11      video: null,
12      btn: false,
13    };
14  },
15  filters: {
16    btnText(btn) {
17return btn ? "继续" : "暂停";
18    },
19    totalText(total) {
20return total > 100 ? 100 : total;
21    },
22  },
23  methods: {
24    async changeFile(file) {
25if (!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 = d();
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;
46for (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
55this.partList = partList;
56this.hash = hash;
57this.sendRequest();
58    },
59    async sendRequest() {
60// 根据100个切⽚创造100个请求(集合)
61      let requestList = [];
62this.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);
68return axios
69            .post("/single3", formData, {
70              headers: { "Content-Type": "multipart/form-data" },
71            })
72            .then((result) => {
73              result = result.data;
74if (de == 0) {
76// 传完的切⽚我们把它移除掉
77this.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 = ("/merge", {
88          params: {
89            hash: this.hash,
90          },
91        });
92        result = result.data;
93if (de == 0) {
94this.video = result.path;
95        }
96      };
97      let send = async () => {
98// 已经中断则不再上传
99if (this.abort) return;
100if (i >= requestList.length) {
101// 都传完了
102          complete();
103return;
104        }
105        await requestList[i]();
106        i++;
107        send();
108      };
109      send();
110    },
111    handleBtn() {
112if (this.btn) {
113//断点续传
114this.abort = false; 115this.btn = false; 116this.sendRequest(); 117return;
118      }
119//暂停上传
120this.btn = true;
121this.abort = true; 122    },
123  },
124 };
125 </script>

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。