背景

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

解决问题

在上传组件的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>

效果

Element-ui上传图片按顺序展示的更多相关文章

  1. element ui表格表头顺序错乱的问题

    因为在项目中两个表格共用了同一个组件, 但由于表头不完全相同, 就通过v-if来控制表头的显示隐藏,没想到造成了表头顺序的错乱, 经过多方查找资料,最后找到了解决方法: 即为每一列el-table-c ...

  2. element ui 上传图片

    upload在form模块,在demo的基础上包个form然后action写地址用?&拼接参数即可

  3. vue项目中使用element ui上传图片到七牛

    1.获取token值 后台有接口调用直接返回token值 //请求后台拿七牛云token async getQiniuToken() { //token let uploadtoken = await ...

  4. 上传图片组件封装 element ui

    // element ui 文档地址: http://element.eleme.io/#/zh-CN <template> <div> <div class=" ...

  5. vue问题三:element ui的upload组件上传图片成功和移除事件

    element ui的upload组件上传图片成功和移除事件: 登录后获取到后台传的token存到中: sessionStorage.setItem("token",data.ob ...

  6. Element UI 中组件this.$message报错

    最近在做毕设的时候,用Element UI中的消息提示message一直报以下的错误: 展示的效果也不好看,没有图标什么的: 但我明明有在main.js引入了element-ui 呀,因为毕设时间很赶 ...

  7. Element ui tree结合Vue使用遇到的一些问题(一)

    下图是一个后台管理系统,展示的是角色列表 当我点击编辑的时候,弹出一个模态框,如下图 功能需求:点击编辑按钮,弹出模态框,选择权限那块,默认选中当前角色拥有的权限. 问题:第一次点击编辑按钮时,不会选 ...

  8. [转]vue Element UI走马灯组件重写

    https://blog.csdn.net/u013750989/article/details/82885482 1.element ui走马灯组件 -- carousel分析一波源代码:carou ...

  9. 基于 vue+element ui 的cdn网站(多页面,都是各种demo)

    前言:这个网站持续更新中...,有网上预览,github上也有源码,喜欢记得star哦,欢迎留言讨论. 网站地址:我的个人vue+element ui demo网站 github地址:yuleGH g ...

随机推荐

  1. 牛客网sql刷题解析-完结

    查找最晚入职员工的所有信息 解题步骤: 题目:查询最晚入职员工的所有信息        目标:查询员工的所有信息 筛选条件:最晚入职           答案: SELECT *--查询所有信息就用* ...

  2. IT兄弟连 HTML5教程 HTML5和HTML的关系

    HTML5开发现在很火爆,是一门技术,更是一个概念.可以让我们的工作模式.交互模式以及对应用和游戏的体验有了翻天覆地的变化,很多人都知道HTML5这门技术,也常把HTML5读作H5(简称).其实一些外 ...

  3. svn版本管理配置权限

    修改svn配置 编辑svnserve.conf文件 第19,20行删掉前面的#--意思就是打开 ancon-access = none  匿名用户不可读 auth-access = write 认证可 ...

  4. 【LOJ#2507】[CEOI2011]Matching(KMP,树状数组)

    [LOJ#2507][CEOI2011]Matching(KMP,树状数组) 题面 LOJ 题解 发现要做的是排名串的匹配. 然后我们考虑把它转成这个位置之前有多少个数小于当前这个数,这样子只要每个位 ...

  5. centos7开启,关闭防火墙

    1.查看防火墙状态 firewall-cmd --state 2.停止防火墙 systemctl stop firewalld.service 3.禁止防火墙开机启动 systemctl disabl ...

  6. bootstrap 自定义模态窗口

    $(".classname").click(function () { $('#mymodel').modal('show'); alert('模态框打开了'); }); $('# ...

  7. MySQL(8)---游标

    Mysql(8)-游标 上一遍博客写了有关存储过程的语法知识 Mysql(7)---存储过程 游标或许你在工作中很少用到,但用不到不代表不去了解它,但你真正需要它来解决问题的时候,再花时间去学习很可能 ...

  8. Spring之 JDBC 异常

    JDBC异常抽象 Spring会将数据操作的异常转换为DataAccessException 解析错误码 SQLErrorCodeSQLExceptionTranslator ErrorCode定义 ...

  9. Vue常用语法

    一.模板语法 1.双大括号表达式 [语法:] {{exp}} 用于向页面输入数据,即页面显示数据. [举例:] <!doctype html> <html lang="en ...

  10. [转]C#操作Outlook

    本文转自:https://blog.csdn.net/yanlovehan/article/details/8500449 //引用Microsoft.Office.Interop.Outlook.d ...