几个点
isMax控制上传图标是否隐藏maxcount控制最大上传数量exceed超出数量限制的提示successremove进行fileList的拼装 在外部表单中使用beforeUpload上传前压缩data拼入自定义参数headers加入token:with-credentials="false"去除session
其它说明
handlePictureCardPreview 在dialog中会出现modal层级的问题,会遮照住放大显示的图片,使用了笨办法来解决
<template>
<div :class="isMax ? 'g-upload-limit' : 'g-upload'">
<!--
https://element.eleme.cn/#/zh-CN/component/upload
with-credentials="false" // 支持发送 cookie 凭证信息
data 上传时附带的额外参数 object
headers 设置上传的请求头部 object
name 上传的文件字段名
:on-change="handleChange"
-->
<el-upload
ref="uploadComponents"
class="g-upload-common"
action="/file/upload_files"
name="file"
multiple
:with-credentials="false"
list-type="picture-card"
:limit="maxcount"
:headers="{ token: token }"
:data="{ filePathType: fileType }"
:on-preview="handlePictureCardPreview"
:on-remove="handleRemove"
:on-success="handleSuccess"
:before-upload="beforeUpload"
:on-exceed="handleExceed"
>
<i class="el-icon-plus" />
</el-upload>
<el-dialog :visible.sync="uploaderVisible">
<img width="100%" :src="uploaderImageUrl" alt="">
</el-dialog>
</div>
</template>
<script>
import { getToken } from '@/utils/auth'
import { deleteFile } from '@/api/common'
export default {
props: {
// 传入最大上传数量
maxcount: {
type: Number,
default: 9
},
// 额外参数
fileType: {
type: Number,
default: 1
}
},
data() {
return {
uploaderVisible: false, // 展示预览图
uploaderImageUrl: '', // 预览图片链接
isMax: false, // 隐藏上传按钮
imgQuality: 0.5, // 压缩质量
fileList: [], // 上传的文件列表, 例如: ['https://xxx.cdn.com/xxx.jpg']
token: ''
}
},
created() {
this.token = getToken()
},
destroyed() {
this.fileList = []
},
methods: {
// 图片改变时修改filelist
handleChange(file, fileList) {
this.fileList = []
fileList.forEach(el => {
// 成功上传 才拼入数组
if (el.response) {
this.fileList.push(el.response.data[0].serviceFileName)
}
})
},
// 预览图片
handlePictureCardPreview(file) {
this.uploaderImageUrl = file.url
this.uploaderVisible = true
setTimeout(() => {
document.querySelector('.v-modal').style.zIndex = '2000'
}, 300)
},
// 上传文件成功
handleSuccess(response, file, fileList) {
this.handleChange(file, fileList)
if (fileList.length >= this.maxcount) {
this.isMax = true
}
},
// 删除文件
handleRemove(file, fileList) {
deleteFile({ deleteFile: [file.response.data[0].serviceFileName] })
if (fileList.length < this.maxcount) {
this.isMax = false
}
this.handleChange(file, fileList)
},
// 文件超出个数限制时的钩子
handleExceed(files, fileList) {
this.$message.error('文件超出上传限制!')
},
dataURItoBlob(dataURI, type) {
var binary = atob(dataURI.split(',')[1])
var array = []
for (var i = 0; i < binary.length; i++) {
array.push(binary.charCodeAt(i))
}
return new Blob([new Uint8Array(array)], { type: 'jpg' })
},
beforeUpload(file) {
const _this = this
return new Promise(resolve => {
const reader = new FileReader()
const image = new Image()
image.onload = (imageEvent) => {
const canvas = document.createElement('canvas')
const context = canvas.getContext('2d')
const width = image.width * _this.imgQuality
const height = image.height * _this.imgQuality
canvas.width = width
canvas.height = height
context.clearRect(0, 0, width, height)
context.drawImage(image, 0, 0, width, height)
const dataUrl = canvas.toDataURL(file.type)
const blobData = _this.dataURItoBlob(dataUrl, file.type)
resolve(blobData)
}
reader.onload = e => { image.src = e.target.result }
reader.readAsDataURL(file)
})
}
}
}
</script>
<style lang='scss'>
.g-upload-limit {
.g-upload-common {
.el-upload--picture-card {
display: none;
}
}
}
</style>
2020-11-11 更新日志
- 服务端返回错误的过滤
- 返回错误之后 删除错误图片预览
- 增加视频 文件等上传功能
<template>
<div :class="isMax ? 'g-upload-limit' : 'g-upload'">
<!--
https://element.eleme.cn/#/zh-CN/component/upload
with-credentials="false" // 支持发送 cookie 凭证信息
data 上传时附带的额外参数 object
headers 设置上传的请求头部 object
name 上传的文件字段名
:on-change="handleChange"
-->
<!-- 图片 -->
<div v-if="filetype === 1">
<el-upload
ref="uploadComponents"
class="g-upload-common"
action="/file/upload_files"
name="file"
multiple
:with-credentials="false"
list-type="picture-card"
:limit="maxcount"
accept="image/*"
:headers="{ token: token }"
:data="{ filePathType: filetype }"
:on-preview="handlePictureCardPreview"
:on-remove="handleRemove"
:on-success="handleSuccess"
:before-upload="beforeUpload"
:on-exceed="handleExceed"
@click="clearUploadedImage"
>
<i class="el-icon-plus" />
<div slot="tip" class="el-upload__tip">只能上传jpg/png文件,最好不超过500kb</div>
</el-upload>
<el-dialog :visible.sync="uploaderVisible">
<img width="100%" :src="uploaderImageUrl" alt="">
</el-dialog>
</div>
<!-- 附件 -->
<div v-if="filetype === 2">
<!-- accept=".xlsx,.xls" -->
<el-upload
ref="uploadComponents"
class="upload-demo"
action="/file/upload_files"
multiple
:with-credentials="false"
name="file"
:data="{ filePathType: filetype }"
accept=".pdf"
:limit="maxcount"
:headers="{ token: token }"
:on-remove="handleRemove"
:on-success="handleSuccess"
:on-exceed="handleExceed"
@click="clearUploadedFile"
>
<el-button size="small" type="primary">点击上传</el-button>
</el-upload>
</div>
<!-- 视频 -->
<div v-if="filetype === 4">
<el-upload
ref="uploadComponents"
class="upload-demo avatar-uploader el-upload--text"
action="/file/upload_files"
:with-credentials="false"
name="file"
:data="{ filePathType: filetype }"
accept=".mp4,.avi"
:limit="maxcount"
:headers="{ token: token }"
:on-success="handleVideoSuccess"
:on-remove="handleRemove"
:before-upload="beforeUploadVideo"
:on-progress="uploadVideoProcess"
:on-exceed="handleExceed"
@click="clearUploadedFile"
>
<!-- 变量this.global.company.showVideoPath如果不存在,就不显示,存在就显示视频 -->
<!-- <video v-if="showVideoPath !='' && !videoFlag" :src="showVideoPath" class="avatar video-avatar" controls="controls">您的浏览器不支持视频播放</video> -->
<!-- <i v-else-if="showVideoPath =='' && !videoFlag" class="avatar-uploader-icon" /> -->
<!-- <el-progress v-if="videoFlag == true" type="circle" :percentage="videoUploadPercent" style="margin-top:30px;" /> -->
<el-button v-if="isShowUploadVideo" slot="trigger" class="video-btn" size="small" type="primary">选取文件</el-button>
<P class="text" style="color: red;">请保证视频格式正确,且不超过100M</P>
</el-upload>
</div>
</div>
</template>
<script>
import { getToken } from '@/utils/auth'
import { deleteFile } from '@/api/common'
export default {
props: {
// 传入最大上传数量
maxcount: {
type: Number,
default: 9
},
// 额外参数
filetype: {
type: Number,
default: 1
}
},
data() {
return {
uploaderVisible: false, // 展示预览图
uploaderImageUrl: '', // 预览图片链接
isMax: false, // 隐藏上传按钮
imgQuality: 0.5, // 压缩质量
fileList: [], // 上传的文件列表, 例如: ['https://xxx.cdn.com/xxx.jpg']
baseFileVOList: [], // 附件的列表
videoList: [], // 上传的视频列表
token: '',
uploadUrl: '', // 上传视频到后台的地址
videoFlag: false, // 是否显示进度条
videoUploadPercent: '', // 进度条的进度,
isShowUploadVideo: true, // 显示上传按钮
uploaderVideoUrl: '', // 预览视频链接
showVideoPath: ''
}
},
created() {
this.token = getToken()
},
destroyed() {
this.fileList = []
this.baseFileVOList = []
this.videoList = []
},
methods: {
// 清空图片
clearUploadedImage() {
this.$refs.uploadComponents.clearFiles()
},
// 清空文件
clearUploadedFile() {
this.$refs.uploadComponents.clearFiles()
},
// 删除没有上传成功的图片
filterImgList(fileList) {
// 深拷贝
// const _fileList = fileList.slice()
// const _fileList = Object.assign({}, fileList)
fileList.forEach((el, i) => {
if (el.response && (el.response.code !== 20000)) {
fileList.splice(i, 1)
}
})
},
// 更新后端返回 20000 的fileList
updateFileList(fileList) {
this.fileList = []
this.baseFileVOList = []
fileList.forEach(el => {
if (el.response && (el.response.code === 20000)) {
if (this.filetype === 1) {
this.fileList.push(el.response.data[0].serviceFileName)
}
if (this.filetype === 2) {
this.baseFileVOList.push({
filePath: el.response.data[0].serviceFileName,
fileName: el.response.data[0].fileName
})
}
}
})
},
// 预览图片
handlePictureCardPreview(file) {
this.uploaderImageUrl = file.url
this.uploaderVisible = true
setTimeout(() => {
document.querySelector('.v-modal').style.zIndex = '2000'
}, 300)
},
// 上传文件成功
handleSuccess(response, file, fileList) {
if (response.code !== 20000) {
this.filterImgList(fileList)
this.$message.error(response.message)
}
this.updateFileList(fileList)
if (fileList.length >= this.maxcount) {
this.isMax = true
}
},
// 删除文件
handleRemove(file, fileList) {
deleteFile({ deleteFile: [file.response.data[0].serviceFileName] })
if (fileList.length < this.maxcount) {
this.isMax = false
}
this.updateFileList(file, fileList)
},
// 文件超出个数限制时的钩子
handleExceed(files, fileList) {
this.$message.error('文件超出上传限制!')
},
dataURItoBlob(dataURI, type) {
var binary = atob(dataURI.split(',')[1])
var array = []
for (var i = 0; i < binary.length; i++) {
array.push(binary.charCodeAt(i))
}
return new Blob([new Uint8Array(array)], { type: 'jpg' })
},
beforeUpload(file) {
const _this = this
return new Promise(resolve => {
const reader = new FileReader()
const image = new Image()
image.onload = (imageEvent) => {
const canvas = document.createElement('canvas')
const context = canvas.getContext('2d')
const width = image.width * _this.imgQuality
const height = image.height * _this.imgQuality
canvas.width = width
canvas.height = height
context.clearRect(0, 0, width, height)
context.drawImage(image, 0, 0, width, height)
const dataUrl = canvas.toDataURL(file.type)
const blobData = _this.dataURItoBlob(dataUrl, file.type)
resolve(blobData)
}
reader.onload = e => { image.src = e.target.result }
reader.readAsDataURL(file)
})
},
// 上传前回调
beforeUploadVideo(file) {
const isLt100M = file.size / 1024 / 1024 < 100
if (['video/mp4'].indexOf(file.type) === -1) { // 'video/ogg', 'video/flv', 'video/avi', 'video/wmv', 'video/rmvb'
this.$message.error('请上传正确的视频格式')
return false
}
if (!isLt100M) {
this.$message.error('上传视频大小不能超过100MB哦!')
return false
}
this.isShowUploadVideo = false
},
// 进度条
uploadVideoProcess(event, file, fileList) {
this.videoFlag = true
this.videoUploadPercent = file.percentage.toFixed(0) * 1
},
// 上传成功回调
handleVideoSuccess(response, file) {
if (response.code === 20000) {
this.isShowUploadVideo = true
this.videoFlag = false
this.videoUploadPercent = 0
this.showVideoPath = response.data[0].serviceFileName
var videoObj = {}
videoObj.url = response.data[0].serviceFileName
videoObj.name = response.data[0].fileName
this.videoList.push(videoObj)
this.$message.success(response.message)
} else {
this.$message.error(response.message)
}
}
}
}
</script>
<style lang='scss'>
.g-upload-limit {
.g-upload-common {
.el-upload--picture-card {
display: none;
}
}
}
</style>