前言
最近做了一个后台,上传商品图片时,要求有以下限制
- 上传图片不大于2M
- 可自定义上传图片的比例
- 图片有拖拽功能
接下来并是我们的实现过程
上传图片不大于2M
<template lang="">
<div>
<el-upload ref="uploadRef" slot="footer" :action="imgConfig.action" list-type="picture-card" multiple
:file-list="imgConfig.fileList" accept="image/jpeg,image/jpg,image/gif,image/png,image/svg"
:before-upload="beforeUpload" :on-success="handleImageSuccess" :on-remove="removeImage"
:headers="imgConfig.headers" :limit='imgConfig.limit' name="images">
<i class="el-icon-plus"></i>
</el-upload>
</div>
</template>
<script>
import vuedraggable from 'vuedraggable';
export default {
props: {
imgConfig: {
action: String, // 图片上传路径
headers: Object, // 请求头
fileList: Array, // 图片列表
limit: Number, // 现在张数
width: Number, // 宽高占比
height: Number
},
},
data() {
return {
isCanUpload: false,
isFirstMount: true // 控制防止重复回显
}
},
created() {
},
mounted() {
},
methods: {
removeImage(file, fileList) {
this.imgConfig.imgList = fileList;
},
beforeUpload(file) {
this.isFirstMount = false
const _self = this;
const isIMAGE = file.type === 'image/jpeg' || 'image/jpg' || 'image/gif' || 'image/png' || 'images/svg';
const isLt2M = file.size / 1024 / 1024 < 2;
if (!isIMAGE) {
this.$message.error('上传文件只能是图片格式!');
}
if (!isLt2M) {
this.$message.error('上传文件大小不能超过 2MB!');
}
return isIMAGE && isLt2M;
},
},
}
</script>
自定义限制上传图片比例
改造beforeUpload 方法
beforeUpload(file) {
this.isFirstMount = false
const _self = this;
const isIMAGE = file.type === 'image/jpeg' || 'image/jpg' || 'image/gif' || 'image/png' || 'images/svg';
const isLt2M = file.size / 1024 / 1024 < 0.5;
if (!isIMAGE) {
this.$message.error('上传文件只能是图片格式!');
}
if (!isLt2M) {
this.$message.error('上传文件大小不能超过 2MB!');
}
var that = this;
// 限制尺寸占比
const isSize = new Promise(function (resolve, reject) {
const reader = new FileReader();
reader.readAsDataURL(file);
reader.onload = (theFile) => {
const image = new Image();
image.src = theFile.target.result;
image.onload = function () {
const { width, height } = image;
if (that.imgConfig.width == null || that.imgConfig.height == null) {
resolve();
}
let valid = width / height !== that.imgConfig.width / that.imgConfig.height;
valid ? reject() : resolve();
}
}
}).then(() => {
return file;
}, () => {
that.$message.error(`图片尺寸宽高比应为:${that.imgConfig.width}:${that.imgConfig.height}!`);
return Promise.reject();
});
return isIMAGE && isLt2M && isSize;
},
图片实现拖拽功能
实现思路
- 引入拖拽功能
- 隐藏之前的图片展示列表
引入拖拽插件 vuedraggable
yarn add vuedraggable
改造之后代码如下
<template lang="">
<div>
<vuedraggable tag="ul" v-model="imgConfig.fileList" class="draggable-box" draggable=".draggable-item"
@start="onDragStart" @end="onDragEnd">
<li v-for="(item,index) in imgConfig.fileList" :key="index + item.url" class="draggable-item">
<el-image :src="item.url" :preview-src-list="[item.url]" style="width: 148px; height: 148px">
</el-image>
<div class="shadow" @click="onRemoveHandler(index)">
<i class="el-icon-delete"></i>
</div>
</li>
<el-upload ref="uploadRef" slot="footer" :action="imgConfig.action" list-type="picture-card" multiple
:file-list="imgConfig.fileList" accept="image/jpeg,image/jpg,image/gif,image/png,image/svg"
:before-upload="beforeUpload" :on-success="handleImageSuccess" :on-remove="removeImage"
:headers="imgConfig.headers" :limit='imgConfig.limit' name="images">
<i class="el-icon-plus"></i>
</el-upload>
</vuedraggable>
</div>
</template>
<script>
import vuedraggable from 'vuedraggable';
export default {
props: {
imgConfig: {
action: String, // 图片上传路径
headers: Object, //
fileList: Array,
limit: Number,
width: Number,
height: Number
},
},
components: {
vuedraggable
},
data() {
return {
isFirstMount: true // 控制防止重复回显
}
},
created() {
},
mounted() {
if (this.imgConfig.fileList.length > 0) {
this.syncElUpload()
}
},
methods: {
// 同步el-upload数据
syncElUpload(val) {
const imgList = val || this.imgConfig.fileList
this.$refs.uploadRef.uploadFiles = imgList.map((v, i) => {
return {
name: 'pic' + i,
url: v.url,
}
})
this.isFirstMount = false
},
// 移除单张图片
onRemoveHandler(index) {
this.$confirm('确定删除该图片?', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
})
.then(() => {
this.imgConfig.fileList = this.imgConfig.fileList.filter((v, i) => {
return i !== index
})
})
.catch(() => { })
},
onDragStart(e) {
e.target.classList.add('hideShadow')
},
onDragEnd(e) {
e.target.classList.remove('hideShadow')
},
handleImageSuccess(res, file, fileList) {
if (res.code != 200) {
this.$message.error(res.message);
return false;
}
fileList.forEach(item => {
if (item.response)
item.url = item.response.data;
});
this.imgConfig.fileList = fileList;
},
removeImage(file, fileList) {
this.imgConfig.imgList = fileList;
},
beforeUpload(file) {
this.isFirstMount = false
const _self = this;
const isIMAGE = file.type === 'image/jpeg' || 'image/jpg' || 'image/gif' || 'image/png' || 'images/svg';
const isLt2M = file.size / 1024 / 1024 < 0.5;
if (!isIMAGE) {
this.$message.error('上传文件只能是图片格式!');
}
if (!isLt2M) {
this.$message.error('上传文件大小不能超过 2MB!');
}
var that = this;
// 限制尺寸占比
const isSize = new Promise(function (resolve, reject) {
const reader = new FileReader();
reader.readAsDataURL(file);
reader.onload = (theFile) => {
const image = new Image();
image.src = theFile.target.result;
image.onload = function () {
const { width, height } = image;
if (that.imgConfig.width == null || that.imgConfig.height == null) {
resolve();
}
let valid = width / height !== that.imgConfig.width / that.imgConfig.height;
valid ? reject() : resolve();
}
}
}).then(() => {
return file;
}, () => {
that.$message.error(`图片尺寸宽高比应为:${that.imgConfig.width}:${that.imgConfig.height}!`);
return Promise.reject();
});
return isIMAGE && isLt2M && isSize;
},
},
}
</script>
<style lang="scss">
.draggable-box {
display: flex;
flex: wrap;
.el-upload-list--picture-card {
display: none; // 隐藏之前的图片列表
}
}
.draggable-item {
margin-right: 5px;
margin-bottom: 5px;
border: 1px solid #ddd;
border-radius: 6px;
position: relative;
overflow: hidden;
width: 148px;
height: 148px;
.shadow {
position: absolute;
top: 0;
right: 0;
background-color: rgba(0, 0, 0, .5);
opacity: 0;
transition: opacity .3s;
color: #fff;
font-size: 20px;
line-height: 20px;
padding: 2px;
cursor: pointer;
}
&:hover {
.shadow {
opacity: 1;
}
}
.el-upload-list__item .is-success {
display: none;
}
}
</style>