说明
Plupload有以下功能和特点:
1、拥有多种上传方式:HTML5、flash、silverlight以及传统的<input type=”file” />。Plupload会自动侦测当前的环境,选择最合适的上传方式,并且会优先使用HTML5的方式。所以你完全不用去操心当前的浏览器支持哪些上传方式,Plupload会自动为你选择最合适的方式。
2、支持以拖拽的方式来选取要上传的文件
3、支持在前端压缩图片,即在图片文件还未上传之前就对它进行压缩
4、可以直接读取原生的文件数据,这样的好处就是例如可以在图片文件还未上传之前就能把它显示在页面上预览
5、支持把大文件切割成小片进行上传,因为有些浏览器对很大的文件比如几G的一些文件无法上传。
Plupload使用步骤
1、引入plupload,可以到github上去下载,我使用的是npm install --save plupload
2、实例化一个plupload对象,传入一个配置参数对象进行各方面的配置。
3、调用plupload实例对象的init()方法进行初始化
4、在plupload实例对象上注册各种你需要的事件。plupload从选取文件到文件上传完成这个过程中,会触发很多事件。我们可以通过这些事件来跟plupload进行交互。
按照项目需求封装好的 plupload.vue
<template>
<div>
<el-tooltip class="item" effect="dark" :content="`支持扩展名:${acceptFiles}`" placement="bottom-start">
<el-button id="browseButton" type="primary" icon="el-icon-upload2">
请选择文件
</el-button>
</el-tooltip>
<em>{{ basicForm.fileName }}</em>
<div v-if="fileRawList.length">
<el-table :data="fileRawList" class="d2-mt-10 d2-mb-10">
<el-table-column
label="文件名"
min-width="100"
>
<template slot-scope="scope">
<span>{{ scope.row.name }}</span>
</template>
</el-table-column>
<el-table-column
label="状态"
min-width="100"
>
<template slot-scope="scope">
<span v-if="scope.row.status === -1">正在计算MD5</span>
<span v-if="scope.row.status === 1 && scope.row.percent === 0">MD5计算完成,准备上传</span>
<span v-if="scope.row.status === 4" style="color: brown">上传失败</span>
<span v-if="scope.row.status === 5" style="color: chartreuse">已上传</span>
<el-progress
v-if="scope.row.percent || scope.row.percent === 0"
:text-inside="true"
:stroke-width="20"
:percentage="scope.row.percent"
:v-if="scope.row.status === 2 || scope.row.status === 1 && scope.row.percent > 0"
/>
</template>
</el-table-column>
<el-table-column
label="操作"
width="70"
>
<template slot-scope="scope">
<el-button type="danger" @click="deleteFile(scope.row)">
删除
</el-button>
</template>
</el-table-column>
</el-table>
<el-button :disabled="uploading" type="danger" @click="uploadStart()">
开始上传
</el-button>
</div>
</div>
</template>
<script>
// plupload参数文档:http://www.phpin.net/tools/plupload/
import plupload from 'plupload/js/plupload.full.min.js'
import FileMd5 from '@/utils/file-md5.js'
import { removeFile } from '@/api/filemgr'
export default {
name: 'Plupload',
props: {
// 文件上传类型限制
acceptFiles: {
type: String,
default: '.png,.jpg,.bmp,.doc,.docx,.xls,.xlsx,.pdf,.rar,.zip'
},
bizType: {
type: String,
default: ''
},
fileList: {
type: Array,
default: () => []
},
limit: {
type: Number,
default: 5
}
},
data() {
return {
up: {},
basicForm: {},
fileRawList: [],
uploading: false
}
},
watch: {
up(val) {
console.log('up')
this.fileRawList = this.fileList.concat(val.files)
},
acceptFiles(val) {
this.up.refresh()
}
// fileList(val) {
// console.log('fileList', val, this.up)
// this.fileRawList = val.concat(this.up.files)
// this.up.refresh()
// }
},
mounted() {
this.pluploadInit()
},
methods: {
pluploadInit() {
var that = this
var uploader = new plupload.Uploader({
browse_button: 'browseButton',
url: globalConfig.BASE_API + '/fileService/bigFileUpload',
chunk_size: '2MB',
headers: that.headers,
multipart: true, // 为true时将以multipart/form-data
max_retries: 1, // 当发生plupload.HTTP_ERROR错误时的重试次数,为0时表示不重试
multi_selection: false, // 是否可以在文件浏览对话框中选择多个文件
filters: {
mime_types: [
{ extensions: that.acceptFiles.replace(/\./g, '') }
],
prevent_duplicates: true, // 不允许选取重复文件
max_file_size: '1024mb' // 最大只能上传400kb的文件
},
init: {
BeforeUpload(up, file) {
// 上传时的附加参数,以键/值对的形式传入
up.setOption('multipart_params', {
'size': file.size,
'md5': file.md5,
'bizType': that.bizType
})
},
FileFiltered(up, files) {
// console.log('FileFiltered', up, files)
},
FilesAdded(up, files) {
console.log('FilesAdded', files)
that.fileRawList.push(...files)
if (that.fileRawList.length > that.limit) {
that.deleteFile(that.fileRawList[0])
}
files.forEach((f) => {
f.status = -1
FileMd5(f.getNative(), (e, md5) => {
f['md5'] = md5
f.status = 1
})
})
},
FilesRemoved(upp, files) {
that.uploading = false
},
FileUploaded(up, file, info) {
if (info.status === 200) {
console.log('FileUploaded', info.response)
const { path } = JSON.parse(info.response).data
file.url = path
that.up.refresh()
that.$emit('onChange', that.fileRawList)
}
},
UploadComplete(up, files) {
that.uploading = false
},
Error(up, args) {
that.uploading = false
}
}
})
uploader.init()
this.up = uploader
},
deleteFile(row) {
console.log(this.fileRawList.indexOf(row))
this.fileRawList.splice(this.fileRawList.indexOf(row), 1)
var file = this.up.getFile(row.id)
file && this.up.removeFile(file)
row.url && removeFile({ filePath: row.url }).then(res => {
if (res.success) {
this.$emit('onChange', this.fileRawList.filter(item => {
return item.url
}))
return
}
this.$message.warning('删除文件出现异常,请与管理员联系!')
})
},
uploadStart() {
this.uploading = true
this.up.start()
}
}
}
</script>
分片
分片的操作是借助spark-md5,同样下载是npm install --save spark-md5,不过为了方便使用,在封装了一层
file-md5.js
/*
* @Author: your name
* @Date: 2020-03-20 15:49:13
* @LastEditTime: 2020-03-23 16:12:23
* @LastEditors: Please set LastEditors
* @Description: In User Settings Edit
* @FilePath: \pc-webapp\src\models\file-md5.js
*/
'use strict'
import SparkMD5 from 'spark-md5'
export default function(file, callback) {
var blobSlice = File.prototype.slice || File.prototype.mozSlice || File.prototype.webkitSlice
var chunkSize = 2097152 // Read in chunks of 2MB
var chunks = Math.ceil(file.size / chunkSize)
var currentChunk = 0
var spark = new SparkMD5.ArrayBuffer()
var fileReader = new FileReader()
fileReader.onload = function(e) {
console.log('read chunk nr', currentChunk + 1, 'of', chunks)
spark.append(e.target.result) // Append array buffer
currentChunk++
if (currentChunk < chunks) {
loadNext()
} else {
callback(null, spark.end())
console.log('finished loading')
}
}
fileReader.onerror = function() {
callback('oops, something went wrong.')
}
function loadNext() {
var start = currentChunk * chunkSize
var end = ((start + chunkSize) >= file.size) ? file.size : start + chunkSize
fileReader.readAsArrayBuffer(blobSlice.call(file, start, end))
}
loadNext()
}
关于使用
file-list 已有的文件列表,比如在修改操作中数据库中已经保存的文件
limit 最大文件个数的限制
biz-type 这是我接口需要的额外参数,其他项目可能不需要
accept-files 支持的文件格式
<plupload
:file-list="theDialogForm.attachJsonArr"
:limit="1"
biz-type="trainModule"
accept-files=".zip,.rar,.xml,.txt,.pdf,.docx,.doc,.xlsx,.xls,.ppt,.pptx,.mp4,.mp3,.gif,.png,.jpg,.jpeg,.bmp"
@onChange="handleFileChange"
/>
handleFileChange(fileList) {
console.log('handleFileChange', fileList)
}