vue基于element封装图片上传组件示例
图片单个上传,支持放大
import imgUpload from '@/components/upload/imgUpload'; // 图片单个上传 <imgUpload class="photoImage" :showTage="DragUploadShowTag" :picDesc="DragUploadpicDesc" :imgUrl="photoId" :isEdit="true" :isDelect="true" :imgMaxWidth="600" :imgMaxHeight="800" :imgMinWidth="50" :imgMinHeight="50" @handleSucess="handleSucess" key="photoPath" v-model="photoId" > </imgUpload>
handleSucess(response) { // 返回文件id ,response // ... 进行业务操作 }, handleRemove(response) { // 返回回调的response // ... 进行业务操作 },
已封装图片组件
<template> <div> <el-upload ref='upload' :id='ref' class='upload-demo' name='file' :style='bodySize' :disabled='formEdit' accept='.jpg,.jpeg,.png,.JPG,.JPEG,.png,.pdf,.PDF' drag :before-upload='beforeUpload' action='/fa-pro-fastdfs/file/uploadFile' :auto-upload='true' :show-file-list='false' :on-success='handleSucess' :on-error='handleError' :headers='improtHeader'> <div v-if='!showImg'> <i class='el-icon-upload' v-if='showTage'></i> <div class='el-upload__text' v-html='showTage'></div> <div class='el-upload__tip' slot='tip' v-html='picDesc'></div> </div> <div v-else class='imgBox'> <div class='img-option' v-if='bigImgShow' @mouseleave='mouseleaveHandle'> <div class='btn'> <i class='el-icon-zoom-in' @click.stop='imgClick' /> <i class='el-icon-upload2' style='margin-left: 20px' @mouseenter='formEdit = false' @mouseleave='formEdit = true' v-if='isEdit' /> <i v-if="isEdit && isDelect" class="el-icon-delete" @click="handleRemove" /> </div> </div> <el-image @mouseenter='mouseenterHandle' z-index='2010' class='img' :src='imgShowUrl + imgFileId' :preview-src-list='[imgShowUrl + imgFileId]' ref='elImg' /> </div> </el-upload> </div> </template> <script> import { accMul } from '@/util/util'; import { delFile } from '@/views/admin/api/fastdfs'; export default { name: 'imgUpload', props: { isEdit: { type: Boolean, default: true, }, isDelect: { type: Boolean, default: false, }, fileID: { type: String, default: '', }, showTage: { type: String, default: () => `将文件拖到此处,或<em>点击上传</em>`, }, //当前行信息 rows: { type: Object, default: () => {}, }, // 图片url value: { type: String, default: '', }, // 图片url imgUrl: { type: String, default: '', }, // formEdit: { // // 是否可上传 // type: Boolean, // default: true // }, imgMinWidth: { // 允许上传的图片最小宽度 type: Number, default: 200, }, imgMinHeight: { // 允许上传的图片最小高度 type: Number, default: 200, }, imgMaxWidth: { // 允许上传的图片最大宽度 type: Number, default: 2000, }, imgMaxHeight: { // 允许上传的图片最大高度 type: Number, default: 2000, }, picDesc: { // 图片上传要求说明 type: String, default: '', }, }, data() { return { loading: true, //图片压缩等待 formEdit: false, ref: 'dragUpload' + +Math.floor(Math.random() * 9999999999999999), // 避免使用时混乱,取随机数值 showImg: false, imgShowUrl: '/fa-pro-fastdfs/file/downloadImage?access_token=' + this.$store.getters.access_token + '&id=', improtHeader: { 'Content-Type': 'multipart/form-data; boundary=;', Authorization: 'Bearer ' + this.$store.getters.access_token, }, tempImgId: '', bodySize: { width: 428, height: 270, }, dialogVisible: false, bigImgShow: false, }; }, computed: { imgId: { get() { return this.imgUrl; }, set(val) { //this.imgFileId = val; }, }, imgFileId: { get() { if (this.imgUrl) { return this.imgUrl; } else { return this.tempImgId; } }, set(val) {}, }, }, watch: { imgId(val) { if (val !== '' || val !== null) { this.imgFileId = val; this.showImg = true; } if (val === '' || val === null) { this.showImg = false; } }, }, created() { if (this.imgUrl !== '' || this.imgUrl !== null) { this.showImg = true; } if (this.imgUrl === '' || this.imgUrl === null) { this.showImg = false; } }, mounted() { this.init(); }, methods: { mouseleaveHandle(e) { this.bigImgShow = false; this.formEdit = false; }, mouseenterHandle(e) { this.bigImgShow = true; this.formEdit = true; }, upload() { this.formEdit = false; }, init() { this.$nextTick(() => { let node = document.getElementById(this.ref).childNodes[0] .childNodes[0]; node.style.height = accMul(0.63, node.offsetWidth) + 'px'; }); }, imgClick() { this.$refs.elImg.clickHandler(); this.bigImgShow = false; this.formEdit = true; }, //上传验证 // beforeUpload(file) { // // 设置允许上传的文件格式 // let uploadExtend = ['jpg', 'jpeg', 'png', 'JPG', 'JPEG', 'png']; // // 获取当前上传文件后缀名并转为小写 // let suffix = file.name // .substr(file.name.lastIndexOf('.')) // .substr(1) // .toLowerCase(); // // 上传文件类型校验 // if (!uploadExtend.includes(suffix)) { // this.$notify({ // title: '提示', // dangerouslyUseHTMLString: true, // type: 'warning', // message: `<p>文件格式不正确,请上传jpg,jpeg,png,JPG,JPEG,png格式的文件</p>` // }); // return false; // } // // 获取允许上传的文件大小 并由MB转为B // let _size = 3; // 默认1MB // let docSize = parseFloat(_size) * 1024 * 1024; // // 上传文件大小校验 // if (file.size > docSize) { // this.$notify({ // title: '提示', // dangerouslyUseHTMLString: true, // type: 'warning', // message: `<p>文件大小过大,请上传${_size}MB以内大小的文件</p>` // }); // return false; // } // // 校验上传图片的尺寸 // const isSize = new Promise((resolve, reject) => { // let minWidth = this.imgMinWidth; // 允许上传的最小宽度 // let minHeight = this.imgMinHeight; // 允许上传的最小宽度 // let maxWidth = this.imgMaxWidth; // 允许上传的最大宽度 // let maxHeight = this.imgMaxHeight; // 允许上传的最大高度 // let _URL = window.URL || window.webkitURL; // let img = new Image(); // img.onload = function() { // let valid = // img.width >= minWidth && // img.width <= maxWidth && // img.height >= minHeight && // img.height <= maxHeight; // valid ? resolve() : reject(); // }; // img.src = _URL.createObjectURL(file); // }).then( // () => { // return file; // }, // () => { // this.$notify({ // title: '提示', // dangerouslyUseHTMLString: true, // type: 'warning', // message: `<p>请上传图片宽度在${this.imgMinWidth}像素-${this.imgMaxWidth}像素,高度在${this.imgMinHeight}像素-${this.imgMaxHeight}像素范围内的照片!</p>` // }); // return Promise.reject(); // } // ); // return isSize; // }, //上传成功 handleSucess(response, file, fileList) { if (response.code === 0) { this.imgFileId = response.data.fileId; this.tempImgId = response.data.fileId; this.showImg = true; this.$emit('handleSucess', response.data.fileId); this.$notify({ title: '成功', message: '上传成功', type: 'success', }); } }, //上传失败 handleError(err, file, fileList) { this.$emit('handleError', err, file, fileList, this.rows); if (err.type === 'error') { this.$notify({ title: '提示', message: '上传失败', type: 'error', }); } }, beforeUpload(file) { console.log(file); // 设置允许上传的文件格式 let uploadExtend = ['jpg', 'jpeg', 'png', 'JPG', 'JPEG', 'png']; let suffix = file.name .substr(file.name.lastIndexOf('.')) .substr(1) .toLowerCase(); // 上传文件类型校验 if (!uploadExtend.includes(suffix)) { this.$notify({ title: '提示', dangerouslyUseHTMLString: true, type: 'warning', message: `<p>文件格式不正确,请上传jpg,jpeg,png,JPG,JPEG,png格式的文件</p>`, }); return false; } // 获取允许上传的文件大小 并由MB转为B const isIE = !!window.ActiveXObject || 'ActiveXObject' in window; let _size = isIE ? 5 : 20; let docSize = parseFloat(_size) * 1024 * 1024; // 上传文件大小校验 if (file.size > docSize) { this.$notify({ title: '提示', dangerouslyUseHTMLString: true, type: 'warning', message: `<p>文件大小过大,请上传${_size}MB以内大小的文件</p>`, }); return false; } let _this = this; return new Promise((resolve, reject) => { let isLt2M = file.size / 1024 / 1024 < 10; // 判定图片大小是否小于10MB if (!isLt2M) { reject(); } let image = new Image(), resultBlob = ''; image.src = URL.createObjectURL(file); if (!isIE) { this.loading = this.$loading({ lock: true, text: '图片压缩中请勿操作页面...', spinner: 'el-icon-loading', background: 'rgba(0, 0, 0, 0.7)', }); } image.onload = () => { let minWidth = this.imgMinWidth; // 允许上传的最小宽度 let minHeight = this.imgMinHeight; // 允许上传的最小宽度 if (image.width < minWidth || image.height < minHeight) { this.$notify({ title: '提示', dangerouslyUseHTMLString: true, type: 'warning', message: `<p>上传图片要求宽度大于${this.imgMinWidth}像素,高度大于${this.imgMinHeight}像素!</p>`, }); reject(); } if (docSize > 1 && !isIE) { this.loading = this.$loading({ lock: true, text: '图片压缩中请勿操作页面...', spinner: 'el-icon-loading', background: 'rgba(0, 0, 0, 0.7)', }); resultBlob = _this.compressUpload(image, file, 1); } // 调用方法获取blob格式,方法写在下边 resolve(resultBlob); }; image.onerror = () => { reject(); }; }); }, /* 图片压缩方法-canvas压缩 */ compressUpload(image, file, size) { let canvas = document.createElement('canvas'); let ctx = canvas.getContext('2d'); let initSize = image.src.length; let { width } = image, { height } = image; canvas.width = width; canvas.height = height; ctx.fillRect(0, 0, canvas.width, canvas.height); ctx.drawImage(image, 0, 0, width, height); // 初始化压缩0.6 let quality = 0.6; let compressData = canvas.toDataURL(file.type || 'image/jpeg', quality); console.log(compressData.length / (1024 * 1024)); console.log(size); while (compressData.length / (1024 * 1024) > size) { quality -= 0.06; console.log(compressData.length / (1024 * 1024)); compressData = canvas.toDataURL('image/jpeg', quality); } this.loading.close(); console.log(this.loading); // 压缩后调用方法进行base64转Blob,方法写在下边 let blobImg = this.dataURItoBlob(compressData); return blobImg; }, /* base64转Blob对象 */ dataURItoBlob(data) { let byteString; if (data.split(',')[0].indexOf('base64') >= 0) { byteString = atob(data.split(',')[1]); } else { byteString = unescape(data.split(',')[1]); } let mimeString = data.split(',')[0].split(':')[1].split(';')[0]; let ia = new Uint8Array(byteString.length); for (let i = 0; i < byteString.length; i += 1) { ia[i] = byteString.charCodeAt(i); } return new Blob([ia], { type: mimeString }); }, // 删除 handleRemove() { let fileId = this.fileID; if (!fileId) { return; } let data = { id: fileId, }; delFile(data).then((res) => { if (res.code == 0) { this.showImg = false; this.$message.success('删除成功'); this.$emit('handleRemove', this.list); } else { this.$message.error(res.msg); } }); }, }, }; </script> <style lang='scss' scoped> .imgBox { position: absolute; top: 0; display: flex; align-items: center; justify-content: center; width: 100%; height: 100%; .img-option { z-index: 3; position: absolute; display: flex; width: 100%; height: 100%; background-color: rgba(0, 0, 0, 0.3); align-items: center; justify-content: center; top: 0px; .btn { color: #fff; font-size: 36px; } } .img { margin: 0 auto; display: block; max-width: 100%; max-height: 100%; width: 100%; height: 100%; // z-index: 2; // 20211002 by gcl edit 当一个页面使用多个imageUpload, 其他放大查看时,索引曾影响展示 } } /deep/ .el-upload__tip { line-height: 18px !important; i { font-style: normal; color: red; } } /deep/ .el-image-viewer__wrapper { z-index: 4; } .big-img { //width: 60%; //height: 80%; /deep/ .el-dialog__body { display: flex; align-items: center; justify-content: center; } } </style>
//封装的工具类中accMul方法
// 乘法: export const accMul = function (arg1, arg2) { arg1 = arg1 ? arg1 : 0; arg2 = arg2 ? arg2 : 0; var m = 0, s1 = arg1.toString(), s2 = arg2.toString(); try { m += s1.split(".")[1].length } catch (e) { } try { m += s2.split(".")[1].length } catch (e) { } return Number(s1.replace(".", "")) * Number(s2.replace(".", "")) / Math.pow(10, m) }
效果如下,目前截图缺少删除按钮,支持上传更新、放大、删除