赞
踩
之前一直使用的element的上传组件,后面发现大于5G的文件上传不了,然后通过各种查询浏览,才发现有插件可以帮助实现。因为没写过所以实现过程还是挺复杂的,需要前后端配合,具体也是参考夏大师博客完成,公司需求不复杂,功能实现就行,所以写的很简易。
插件:vue-simple-uploader
<template> <div id="global-uploader"> <!-- 上传 --> <uploader ref="uploader" :options="options" :auto-start="false" class="uploader-example" :file-status-text="statusText" @file-added="onFileAdded" @file-success="onFileSuccess" @file-progress="onFileProgress" @file-error="onFileError" > <uploader-unsupport /> <uploader-drop style="display:flex;padding:10px;align-items: center;justify-content: center;" > <p>拖动文件到此 或</p> <uploader-btn id="global-uploader-btn" ref="uploadBtn" :attrs="attrs"> <i class="el-icon-upload" /> <span style="margin-left:5px;">选择文件</span></uploader-btn> </uploader-drop> <uploader-list v-show="panelShow"> <div slot-scope="props" class="file-panel"> <!-- <div class="file-title"> <h4>文件列表</h4> </div> --> <ul class="file-list"> <li v-for="file in props.fileList" :key="file.id"> <uploader-file ref="files" :class="'file_' + file.id" :file="file" :list="true" /> </li> <div v-if="!props.fileList.length" class="no-file"> 暂无待上传文件 </div> </ul> </div> </uploader-list> </uploader> </div> </template> <script> import seversConfig from '../../../vue.config' const SparkMD5 = require('spark-md5') export default { name: 'GlobalUploader', props: { params: { type: Object, default: function() { return {} } } }, data() { return { serverAddress: seversConfig.devServer.proxy['/api'].target.split( '/api' )[0], uploadIng: false, // 上传状态 panelShow: false, // 选择文件后,展示上传panel attrs: { // 接受的文件类型,形如['.png', '.jpg', '.jpeg', '.gif', '.bmp'...] // accept: ACCEPT_CONFIG.getAll() // accept: [ // '.png', // '.jpg', // '.jpeg', // '.gif', // '.bmp', // '.tar', // '.txt', // '.exe', // '.rar', // '.7z', // '.wim', // '.zip', // '.doc', // '.xls', // '.xlsx', // '.pdf' // ] }, statusText: { success: '上传成功', error: '上传失败', uploading: '正在上传', paused: '暂停上传', waiting: '等待上传' }, options: { target: `/api/addfilebig`, // 目标上传 URL chunkSize: 10 * 1024 * 1024, // 分块大小 fileParameterName: 'file', // 上传文件时文件的参数名,默认file simultaneousUploads: 1, // 并发数 maxChunkRetries: 3, // 最大自动失败重试上传次数 testChunks: true, // 是否开启服务器分片校验 -> 即上传前判断块是否已经存在 // 服务器分片校验函数,秒传及断点续传基础 /* 服务器分片校验函数,判断秒传及断点续传,传入的参数是Uploader.Chunk实例以及请求响应信息 reponse码是successStatuses码时,才会进入该方法 reponse码如果返回的是permanentErrors 中的状态码,不会进入该方法,直接进入onFileError函数 ,并显示上传失败 reponse码是其他状态码,不会进入该方法,正常走标准上传 checkChunkUploadedByResponse函数直接return true的话,不再调用上传接口 */ checkChunkUploadedByResponse: function(chunk, message) { // console.log(message, 'msg') const objMessage = JSON.parse(message) if (parseInt(objMessage.code) === 2) { return true } return (objMessage.data || []).indexOf(chunk.offset + 1) >= 0 }, headers: { // 在header中添加的验证,请根据实际业务来 // Authorization: 'Bearer ' + Ticket.get().access_token }, // 额外的自定义查询参数 query: (file, chunk) => { // console.log(file, 'fileQuery') file.params = this.params return { ...file.params } } } } }, methods: { // 一个文件选中 onFileAdded(file, event) { // console.log(this.$refs.uploader, 'uploader') this.panelShow = true // 调用校验MD5方法 this.computeMD5(file) // 将额外的参数赋值到每个文件上,解决了不同文件使用不同params的需求 file.params = this.params this.uploadIng = true this.$emit('getLoading', this.uploadIng) }, computeMD5(file) { const loading = this.$loading({ lock: true, text: `正在计算MD5`, spinner: 'el-icon-loading', background: 'rgba(0, 0, 0, 0.7)' }) const fileReader = new FileReader() const time = new Date().getTime() const blobSlice = File.prototype.slice || File.prototype.mozSlice || File.prototype.webkitSlice let currentChunk = 0 const chunkSize = this.options.chunkSize const chunks = Math.ceil(file.size / chunkSize) const spark = new SparkMD5.ArrayBuffer() // 文件状态设为"计算MD5" // this.statusSet(file.id, 'md5') file.pause() loadNext() fileReader.onload = e => { spark.append(e.target.result) if (currentChunk < chunks) { currentChunk++ loadNext() // 实时展示MD5的计算进度 this.$nextTick(() => { console.log( '校验MD5 ' + ((currentChunk / chunks) * 100).toFixed(0) + '%' ) }) } else { const md5 = spark.end() loading.close() this.computeMD5Success(md5, file) console.log( `MD5计算完毕:${file.name} \nMD5:${md5} \n分片:${chunks} 大小:${ file.size } 用时:${new Date().getTime() - time} ms` ) } } fileReader.onerror = function() { this.error(`文件${file.name}读取出错,请检查该文件`) loading.close() file.cancel() } function loadNext() { const start = currentChunk * chunkSize const end = start + chunkSize >= file.size ? file.size : start + chunkSize fileReader.readAsArrayBuffer(blobSlice.call(file.file, start, end)) } }, // MD5校验成功 computeMD5Success(md5, file) { file.uniqueIdentifier = md5 file.resume() // 开始上传 // this.statusRemove(file.id) }, // 文件上传进度 onFileProgress(rootFile, file, chunk) { this.uploadIng = true this.$emit('getLoading', this.uploadIng) console.log( `上传中 ${file.name},chunk:${chunk.startByte / 1024 / 1024} ~ ${chunk.endByte / 1024 / 1024}` ) }, onFileSuccess(rootFile, file, response, chunk) { const res = JSON.parse(response) // console.log(res, 'res') if (parseInt(res.code) === 1) { // file.cancel() } // 服务器自定义的错误,这种错误是Uploader无法拦截的 if (parseInt(res.code) === 0) { return } else { file.cancel() this.$emit('getUrl', res.url) } this.uploadIng = false this.$emit('getLoading', this.uploadIng) // 如果服务端返回需要合并 // if (res.needMerge) { // // 合并接口调用 // addfilebig({ // tempName: res.tempName, // fileName: file.name, // ...file.params // }) // .then(data => { // // 文件合并成功 // Bus.$emit('fileSuccess', data) // }) // .catch(e => {}) // // 不需要合并 // } else { // Bus.$emit('fileSuccess', res) // console.log('上传成功') // } }, onFileError(rootFile, file, response, chunk) { console.log(response, 'fileError') } } } </script> <style lang="scss" scoped> .uploader-example { width: 100%; // padding: 15px; // margin: 40px auto 40px; font-size: 12px; // border: 1px solid #000 !important; } .uploader-example .uploader-btn { width: 80px; height: 24px; // line-height: 1; display: flex; justify-content: center; align-items: center; white-space: nowrap; cursor: pointer; background-color: #1890ff; border: 1px solid #1890ff; border-color: #1890ff; color: #fff; text-align: center; box-sizing: border-box; outline: none; margin: 0; margin-left: 10px; border-radius: 3px; transition: 0.1s; font-weight: 400; -webkit-user-select: none; padding: 7px 15px; font-size: 12px; :hover { background-color: #1890ff; } } .uploader-example .uploader-list { max-height: 440px; overflow: auto; overflow-x: hidden; overflow-y: auto; ul { margin: 0 !important; padding-left: 0 !important; li { ::marker { unicode-bidi: isolate; font-variant-numeric: tabular-nums; text-transform: none; text-indent: 0px !important; text-align: start !important; text-align-last: start !important; } list-style-type: none !important; } } .uploader-file { // border-bottom: 0; } } .uploader-unsupport { :hover { background-color: #1890ff; } } .uploader-btn { display: inline-block; } .no-file { padding: 20px; text-align: center; border-left: 1px solid #cccccc; border-bottom: 1px solid #cccccc; border-right: 1px solid #cccccc; } </style>
<template> <uploadFile :params="bigFileParams" @getUrl="getUrl" @getLoading="getLoading" /> </template> <script> export default { data(){ return{ bigFileParams: { // 大文件参数 }, uploadIng: false } }, methods:{ // 大文件上传相关 getUrl(url) { // 获取上传完后的url this.postObj.url = url // console.log(url, 'url2222222222') }, // 上传loading getLoading(uploadIng) { this.uploadIng = uploadIng } } } </script>
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。