赞
踩
vue-simple-uploader文档
simple-uploader.js文档
npm install vue-simple-uploader --save
因为我是单独使用的子组件,所以我只在子组件中使用,也可以放在main.js中
import uploader from 'vue-simple-uploader'
import Vue from 'vue'
Vue.use(uploader)
<template> <div> <uploader ref="simUploader" :options="options" :autoStart="autoStart" :fileStatusText="fileStatusText" class="uploader" @file-added="onFileAdded" @files-added="onFilesAdded" @file-success="onFileSuccess" @file-progress="onFileProgress" @file-error="onFileError" > <uploader-unsupport></uploader-unsupport> <uploader-btn class="uploader-wrapper" :attrs="attrs"> <uploader-drop :attrs="attrs"> <img class="img-upload" :src="require('#/assets/images/icon-upload.png')" alt="" /> <div class="uploader-drop-text"> 可直接点击或将文件拖拽至框内上传 </div> </uploader-drop> </uploader-btn> <div class="uploader-list"> <div v-for="(item, index) in uploaderList" :key="item.id + index" class="uploader-list-item"> <uploader-file :file="item" hidden-complete list> <template #default="{ extension, file, formatedSize, progress, status }"> <div class="uploader-list-item__inner"> <i class="el-icon-document"></i> <template> <el-tooltip :content="file.name"> <span class="file-info"> {{ file.name }} </span> </el-tooltip> <md-el-icon name="el-icon-edit-outline edit-icon" @click="editFile(index)" style="font-size:16px" ></md-el-icon> </template> <span>{{ formatedSize }}</span> <div v-if="file.name.split('.').pop() === 'zip' && enableUnzip"> <el-radio-group v-model="file.enableUnzip"> <el-radio :label="true"> <span>解压</span> </el-radio> <el-radio :label="false"> <span>不解压</span> </el-radio> </el-radio-group> </div> <!-- 状态分为2种, 上传,解压 --> <div style="width:30%"> <div v-if="item.enableUnziping"> <el-progress :percentage="item.progress" :status="item.status ? 'exception' : 'success'" :show-text="false" text-inside ></el-progress> </div> <div v-else> <el-progress :percentage="progress * 100" :status="item.status ? 'exception' : 'success'" :show-text="false" text-inside ></el-progress> </div> </div> <div style="width:50px"> {{ item.enableUnzipStatus ? item.enableUnzipStatus : item.status ? fileStatusText.error : fileStatusText[status] }} </div> <i class="el-icon-circle-close" @click="deleteFile(item, index)" style="font-size:16px" ></i> </div> </template> </uploader-file> </div> </div> </uploader> </div> </template>
由于是对原simple-upload.js做的封装,大多数的配置可以参考原生js文档,部分配置与原生有些许不同,请注意仔细查看相关参考文档。
options: { target: this.uploadUrl, //目标上传地址URL,默认值为 '/'。 singleFile: this.singleFile, // 单文件上传 默认 false chunkSize: 5 * 1024 * 1024, // 分片时按照该值来分。最后一个上传分片的大小是可能是大于等于1倍的这个值但是小于两倍的这个值大小 forceChunkSize: true, // 是否强制所有的块都一定小于等于chunkSize fileParameterName: 'file', // 上传文件时文件的参数名,默认file maxChunkRetries: 5, // 最大自动失败重试上传次数,值可以是任意正整数,如果是 undefined 则代表无限次,默认 0 testChunks: true, // 是否开启服务器分片校验 simultaneousUploads: 6, // 并发上传数,默认 3 chunkRetryInterval: null, // 重试间隔,值可以是任意正整数,如果是 null 则代表立即重试,默认null query: {}, // 其他额外的参数 headers: this.uploadHeaders, // 额外的一些请求头,例如有时我们需要在header中向后台传递token,默认为对象: {} processParams: (params, file) => { // 处理请求参数 一般用于修改参数名字或者删除参数 这里我处理了压缩文件是否可以解压 if (this.enableUnzip && file.enableUnzip) { } params.md5 = file.md5 params.identifier = file.identifier return params } }, fileStatusText: { success: '成功', error: '出错了', uploading: '上传中', paused: '暂停', waiting: '等待中' }, autoStart:false, // 默认 true, 是否选择文件后自动开始上传。
onFileAdded(file) { //文件添加成功后可以进行文件格式、文件名称、文件大小、是否可重名等限制 // 计算MD5,完成后开始上传操作 this.computeMD5(file, () => { this.$emit('addFile', file) }) } onFilesAdded(files, fileList) { console.log('on-files-added', files, fileList) }, // 文件上传成功后,在“上传完成”的回调中,通过服务端合并文件 onFileSuccess(rootFile, file, message, chunk) { // 如果 需要合并 if (this.needMerge) { request.mergerFile({ tempName: res.tempName, fileName: file.name, ...file.params, }).then(data => { // 文件合并成功 this.$emit('fileSuccess', data); }).catch(e => {}); // 不需要合并 } else { this.$emit('fileSuccess', res); console.log('上传成功'); } }, onFileProgress(rootFile, file, chunk) { // 文件进度的回调 // console.log('on-file-progress', rootFile, file, chunk) }, onFileError(rootFile, file, message, chunk) { console.log('on-file-error', rootFile, file, message, chunk) },
断点续传及秒传的基础是要计算文件的MD5,这是文件的唯一标识,然后服务器根据MD5进行判断,是进行秒传还是断点续传。在file-added事件之后,就计算MD5,我们最终的目的是将计算出来的MD5加到参数里传给后台,然后继续文件上传的操作,详细的思路步骤是:
1)把uploader组件的autoStart设为false,即选择文件后不会自动开始上传
2)先通过 file.pause()暂停文件,然后通过H5的FileReader接口读取文件
3)将异步读取文件的结果进行MD5,这里我用的加密工具是spark-md5,你可以通过npm install spark-md5 --save来安装,也可以使用其他MD5加密工具。
4)file有个属性是uniqueIdentifier,代表文件唯一标示,我们把计算出来的MD5赋值给这个属性 file.uniqueIdentifier = md5,这就实现了我们最终的目的。
5)通过file.resume()开始/继续文件上传。
/** * 计算md5,实现断点续传及秒传 * @param file * @param callback 计算完成的回调 */ computeMD5(file, callback) { 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 = this.options.chunkSize // 10 * 1024 * 1000; let chunks = Math.ceil(file.size / chunkSize) // 总块数 let spark = new SparkMD5.ArrayBuffer() file.pause() file.md5Status = '解析中' file.temp_identifier = Math.random() // 先添加一个临时的, 前端自己用 loadNext() fileReader.onload = e => { spark.append(e.target.result) if (currentChunk < chunks) { currentChunk++ loadNext() } else { let md5 = spark.end() file.identifier = this.folderId + '/' + md5 this.computeMD5Success(md5, file) file.md5Status = '解析完成' console.log( `MD5计算完毕:${file.name} \nMD5:${md5} \n分片:${chunks} 大小:${ file.size } 用时:${new Date().getTime() - time} ms` ) callback && callback() } } fileReader.onerror = function() { this.$notify({ title: '错误', message: `文件${file.name}读取出错,请检查该文件`, type: 'error', duration: 2000 }) 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)) } }, computeMD5Success(md5, file) { // 将自定义参数直接加载uploader实例的opts上 file.md5UniqueIdentifier = md5 file.isMergeComplete = false if (this.autoStart) { // 自动上传 file.resume() } },
给file的uniqueIdentifier 属性赋值后,请求中的identifier即是我们计算出来的MD5
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。