1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173
| <template> <div id="app"> <el-upload action drag :auto-upload="false" :show-file-list="false" :on-change="handleChange"> <i class="el-icon-upload"></i> <div class="el-upload__text">将文件拖到此处,或<em>点击上传</em></div> <div class="el-upload__tip" slot="tip">大小不超过 200M 的视频</div> </el-upload>
<div class="progress-box"> <span>上传进度:{{ percent.toFixed() }}%</span> <el-button type="primary" size="mini" @click="handleClickBtn">{{ upload | btnTextFilter}}</el-button> </div>
<div v-if="videoUrl"> <video :src="videoUrl" controls /> </div> </div> </template>
<script> import SparkMD5 from "spark-md5" import axios from "axios"
export default { name: 'App3', filters: { btnTextFilter(val) { return val ? '暂停' : '继续' } }, data() { return { percent: 0, videoUrl: '', upload: true, percentCount: 0 } }, methods: { async handleChange(file) { if (!file) return this.percent = 0 this.videoUrl = '' const fileObj = file.raw let buffer try { buffer = await this.fileToBuffer(fileObj) } catch (e) { console.log(e) }
const chunkSize = 2097152, chunkList = [], chunkListLength = Math.ceil(fileObj.size / chunkSize), suffix = /\.([0-9A-z]+)$/.exec(fileObj.name)[1]
const spark = new SparkMD5.ArrayBuffer() spark.append(buffer) const hash = spark.end()
let curChunk = 0 for (let i = 0; i < chunkListLength; i++) { const item = { chunk: fileObj.slice(curChunk, curChunk + chunkSize), fileName: `${hash}_${i}.${suffix}` } curChunk += chunkSize chunkList.push(item) } this.chunkList = chunkList this.hash = hash this.sendRequest() },
sendRequest() { const requestList = [] this.chunkList.forEach((item, index) => { const fn = () => { const formData = new FormData() formData.append('chunk', item.chunk) formData.append('filename', item.fileName) return axios({ url: '/single3', method: 'post', headers: { 'Content-Type': 'multipart/form-data' }, data: formData }).then(res => { if (res.data.code === 0) { if (this.percentCount === 0) { this.percentCount = 100 / this.chunkList.length } this.percent += this.percentCount this.chunkList.splice(index, 1) } }) } requestList.push(fn) })
let i = 0 const complete = () => { axios({ url: '/merge', method: 'get', params: { hash: this.hash } }).then(res => { if (res.data.code === 0) { this.videoUrl = res.data.path } }) } const send = async () => { if (!this.upload) return if (i >= requestList.length) { complete() return } await requestList[i]() i++ send() } send() },
handleClickBtn() { this.upload = !this.upload if (this.upload) this.sendRequest() },
fileToBuffer(file) { return new Promise((resolve, reject) => { const fr = new FileReader() fr.onload = e => { resolve(e.target.result) } fr.readAsArrayBuffer(file) fr.onerror = () => { reject(new Error('转换文件格式发生错误')) } }) } } } </script>
<style scoped> .progress-box { box-sizing: border-box; width: 360px; display: flex; justify-content: space-between; align-items: center; margin-top: 10px; padding: 8px 10px; background-color: #ecf5ff; font-size: 14px; border-radius: 4px; } </style>
|