背景

不知道你上传图片的时候有没有过这样的情况,批量上传多张图片,可能因为图片大小或者网络问题,导致图片返回的顺序和上传时的顺序不一样。因为我们公司是做电商的,即使我们的支持拖动排序,运营还是希望图片能够严格的按照他们上传的顺序展示。

解决问题

在上传组件的on-success的方法中,有3个参数 response, file, fileList 其中fileList就是之前上传成功图片的集合,且upload组件提供了clearFiles方法,用来清空fileList,每次上传成功,我们调用clearFiles方法就行了

上代码

<template>
<!-- 上传单张图片 -->
<div v-if="!multiple" class="image-item">
<div class="image-wrap" v-if="imgUrl">
<img :src="imgUrl" :style="imgStyle" />
<div class="icon-wrap" @click.stop="removeFile">
<i class="el-icon-delete"></i>
</div>
</div>
<el-upload
v-else
ref="imageUpload"
action="//up.qbox.me"
:before-upload="beforeUpload"
:on-success="handleSuccess"
class="image-uploader"
:on-error="onError"
:data="form"
:show-file-list="false"
:disabled="loading"
accept="image/*">
<i :class="loading ? 'el-icon-loading' : 'el-icon-plus'" :style="imgStyle"></i>
</el-upload>
</div>
<!-- 上传多张图片 -->
<div class="image-list" v-else>
<draggable v-model="showImgList" :options="{group:'image'}" @change="dragChange">
<div v-for="(image, index) in showImgList" :key="index" class="image-wrap">
<img :src="imgUrl" :style="imgStyle" />
<div class="icon-wrap" @click.stop="removeFile(index)">
<i class="el-icon-delete"></i>
</div>
</div>
<el-upload
ref="imageListUpload"
action="//up.qbox.me"
:before-upload="beforeUpload"
:on-success="handleSuccess"
class="image-uploader"
:on-error="onError"
:data="form"
multiple
:disabled="loading"
:show-file-list="false"
accept="image/*">
<i :class="loading ? 'el-icon-loading' : 'el-icon-plus'" :style="imgStyle"></i>
</el-upload>
</draggable>
</div>
</template>
<script type="text/babel">
/**
* 上传图片或文件
*/
import md5 from 'blueimp-md5'
import draggable from 'vuedraggable' export default {
props: {
// 接收和返回的数据
data: {
type: [Array, String, Object],
default: () => {
return ''
}
},
// 上传多个文件时,文件限制的个数
limit: {
type: Number,
default: () => {
return 100
}
},
// 一次上传多个
multiple: {
type: Boolean,
default: false,
},
//图片展示的宽度
imgWidth: {
type: Number,
default: 150,
},
imgHeight: {
type: Number,
default: 150,
},
//期望上传图片的宽度
rule: [ Object, Function ]
},
data() {
return {
imgUrl: '',
imageCdn: '', //图片的cdn
form: {
token: '', //七牛上传的token
},
showImgList: [],
fileList: [],
clipboard: false,
isDrag: false,
handleSuccess: null,
loading: false,
}
},
components: { draggable },
watch: {
data: {
handler(value) {
if (!this.multiple) {
this.imgUrl = value
} else if (this.multiple) {
this.showImgList = value
}
},
immediate: true
}
},
computed: {
imgStyle() {
return {
width: this.imgWidth + 'px',
height: this.imgHeight + 'px',
lineHeight: this.imgHeight + 'px',
}
}
},
mounted() {
//防抖
this.handleSuccess = _.debounce(this.uploadSuccess, 500)
},
methods: {
beforeUpload(file) {
if (file.type.split('/')[0] === 'image') {
let tempSize = file.size / 5242880
if (tempSize > 1) {
this.$message.error('图片尺寸不得大于5M!')
return false
}
}
this.loading = true
let tempNames = file.name.split('.')
let fileType = tempNames[tempNames.length - 1]
let curr = (+new Date()).toString()
let random = Math.random() * 10000
let md5Str = md5(`${curr}${random}${file.name}`)
this.form.key = `ai-admin/${md5Str}.${fileType}`
},
async uploadSuccess(response, file, fileList) {
try {
for (let fileInfo of fileList) {
let imageInfo = await this.getImageInfo(fileInfo.response.key)
if (this.rule) {
this.rule(imageInfo, (error) => {
if (error) {
throw(error)
}
})
}
if (imageInfo.width > 2048 || imageInfo.height > 2048) {
throw(new Error('图片长或者宽不能超过2048'))
} else {
if (this.type === 'image') {
this.imgUrl = response.key
this.$emit('update:data', response.key)
} else {
if (this.showImgList.length >= this.limit) { // 限制图片张数
this.showImgList.length = this.limit
throw(new Error(`最多上传 ${this.limit} 张图片`))
}
this.showImgList.push(imageInfo)
this.$emit('update:data', this.showImgList)
}
}
}
} catch (error) {
this.$message.error(error.message)
} finally {
this.loading = false
this.$refs.imageListUpload && this.$refs.imageListUpload.clearFiles()
this.$refs.imageUpload && this.$refs.imageUpload.clearFiles()
}
},
removeFile(index) {
this.$confirm('确定删除该图片吗?', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).then(() => {
if (this.type === 'image') {
this.$emit('update:data', typeof this.data === 'object' ? {} : '')
} else {
this.showImgList.splice(index, 1)
this.$emit('update:data', this.showImgList)
}
})
},
onError() {
this.$message.error('上传文件失败')
},
getImageInfo(url){
return new Promise((resolve, reject)=>{
let image = new Image()
image.src = `${this.imageCdn}${url}`
image.onload = () => {
resolve({
image: url,
width: image.width,
height: image.height
})
}
image.onerror = () => {
reject(new Error('Could not load image at ' + url));
};
})
},
dragChange() {
this.$emit('update:data', this.showImgList)
},
handleRemove(file, fileList) {
let imgList = fileList.map(item => {
return item.response.key
})
this.$emit('update:data', imgList)
},
handlerClipboard(event) {
if (this.clipboard) {
const rawFile = getImageFromClipboard(event)
if (rawFile) {
this.$refs.elUpload.handleStart(rawFile)
this.$refs.elUpload.$refs['upload-inner'].upload(rawFile)
}
}
},
}
}
</script>
<style lang="less" scoped>
.image-list, .image-item {
display: flex;
.image-wrap {
position: relative;
display: inline-block;
box-sizing: content-box;
margin: 0 8px 8px 0;
vertical-align: top;
&:hover {
.icon-wrap {
opacity: 1;
}
}
.icon-wrap {
position: absolute;
left: 0;
bottom: 0;
width: 100%;
height: 30px;
cursor: default;
text-align: center;
color: #fff;
opacity: 0;
font-size: 20px;
background-color: rgba(0, 0, 0, .7);
transition: opacity .3s;
.el-icon-zoom-in {
cursor: pointer;
margin-right: 8px;
}
.el-icon-delete {
cursor: pointer;
}
}
}
}
.image-item {
display: inline-flex;
}
/deep/.image-uploader {
display: inline-block;
.el-upload {
border: 1px dashed #d9d9d9;
border-radius: 6px;
cursor: pointer;
position: relative;
overflow: hidden;
[class^="el-icon"] {
font-size: 28px;
color: #8c939d;
text-align: center;
}
&:hover {
border-color: #409EFF;
}
}
}
</style>

注意

这是我封装的上传图片的组件,支持 类v-model的传参方式,上传多张图时支持拖动,写图片规则(例如宽高是多少),删除图片

特别注意:因为我们还封装了图片组件,在这里被我替换了,所以图片展示有上面的代码可能有点问题,稍微改下就行

用法(只允许上传正方形的图)

<template>
<image-upload :data.sync="image" :rule="rule"></image-upload>
</template>
<script>
export default {
data(){
let validate = ({ width, height }, callback) => {
if (width === height) {
callback()
} else {
callback(new Error('请上传正方形的图'))
}
}
return {
rule: validate,
image: ''
}
},
}
</script>

效果

最新文章

  1. [转]JUnit-4.11使用报java.lang.NoClassDefFoundError: org/hamcrest/SelfDescribing错误
  2. C#一元运算重载的深入理解
  3. 【Oracle】表空间容量修改
  4. (三)Linux命令基本格式以及文件处理命令
  5. 一些App的User-Agent
  6. Sublime怎样新建HTML文档
  7. bzoj 1997: [Hnoi2010]Planar
  8. HTTP协议详解(经典)
  9. 《Code Complete》ch.11 变量名的力量
  10. IOS—通过ChildViewController实现view的切换
  11. select.poll,epoll的区别与应用
  12. Linux(UBUNTU) 下安装Eclipse
  13. webstorm2017破解
  14. Android自定义View(二、深入解析自定义属性)
  15. Dynamics CRM2016 新功能之Solution enhancements
  16. c#位运算基本概念与计算过程
  17. 作业一 :关于C语言
  18. laravel项目安装
  19. c++ CreateProcess调用dos命令
  20. 决策树模型组合之随机森林与GBDT(转)

热门文章

  1. pytest框架优化——将异常截屏图片加入到allure报告中
  2. javascript 模块化 (切记:学习思想)
  3. Spring5源码解析2-register方法注册配置类
  4. wpf source path
  5. 关于UIScollView中的contentOffset的理解
  6. 微信小程序动画之弹出菜单
  7. CODING 签约天津大学,助力高校“产学”接轨
  8. 记录C#-WPF线程中如何修改值
  9. docker安装执行问题
  10. 浅谈P/NP问题