Vue 图片压缩上传: element-ui + lrz
步骤
- 安装依赖包
npm install --save lrz
- 在
main.js
里引入import lrz from 'lrz'
- 封装
compress
函数 - 封装上传组件
upload-image
- 在 vue 文件中 使用
封装 compress
函数
// eslint-disable
/** @format */
// base64编码转File
export function dataURLtoFile(dataurl, filename) {
var arr = dataurl.split(','),
mime = arr[0].match(/:(.*?);/)[1],
bstr = atob(arr[1]),
n = bstr.length,
u8arr = new Uint8Array(n);
while (n--) {
u8arr[n] = bstr.charCodeAt(n);
}
return new File([u8arr], filename, { type: mime });
}
// main function.
export function compress(file, fileList, that, reference) {
if (file.status != 'ready') {
return;
}
let index = reference.uploadFiles.indexOf(file);
// jpg/jpeg/bmp/gif/png
let isJPG =
file.raw.type === 'image/jpg' ||
file.raw.type === 'image/jpeg' ||
file.raw.type === 'image/png' ||
file.raw.type === 'image/gif' ||
file.raw.type === 'image/bmp'
const isLt20M = file.size / 1024 / 1024 < 20;
if (!isJPG) {
that.$message.error('不支持的格式,请上传jpg/jpeg/bmp/gif/png格式的图片!');
fileList.splice(fileList.indexOf(file), 1);
return;
}
if (!isLt20M) {
that.$message.error('上传图片大小不能超过 20MB!');
fileList.splice(fileList.indexOf(file), 1);
return;
}
if (isJPG & isLt20M) {
if (isLt2M(file)) {
// pdf不压缩
submit(reference, file);
} else {
let options = {};
lrz(file.raw, options)
.then(rst => {
let tempFile = dataURLtoFile(rst.base64, rst.origin.name);
tempFile.uid = rst.origin.uid;
reference.uploadFiles[index].raw = tempFile;
reference.uploadFiles[index].size = rst.fileLen;
})
.catch(function (error) {
// 失败时执行
if (error) {
// IE报错
if (error.name == 'TypeError' && error.message == '对象不支持此操作') {
that.$message.error('当前浏览器不支持上传大于2M的文件,请更换浏览器!');
}
// 图片格式问题
else if ((error + '').indexOf('加载图片文件失败') > -1) {
that.$message.error('系统未能识别当前上传图片,请更换!');
}
}
fileList.splice(fileList.indexOf(file), 1);
})
.always(function () {
//不管成功或失败都会执行
submit(reference, file);
});
}
}
}
// 判断文件大小是否小于2M
function isLt2M(file) {
if (file.raw.type === 'application/pdf') {
return true;
} else {
return file.size / 1024 / 1024 < 2;
}
}
function submit(reference, file) {
let submitFlag = true;
if (reference.multiple) {
for (let item of reference.uploadFiles) {
if (item.status != 'ready') {
continue;
}
if (!isLt2M(item)) {
submitFlag = false;
break;
} else {
submitFlag = true;
}
}
} else {
if (!isLt2M(file)) {
submitFlag = false;
} else {
submitFlag = true;
}
}
if (submitFlag) {
reference.submit();
return;
}
}
封装上传组件upload-image
<template>
<div class="upload-component-container">
<div class="upload-section">
<!-- 上传主体 -->
<el-row>
<el-upload
ref="imageUploadRef"
:headers="token"
:action="uploadUrl"
:auto-upload="false"
list-type="picture-card"
:file-list="imageList"
:on-change="resize"
:on-remove="handleRemove"
:on-preview="handlePreview"
:on-success="handleSuccess"
:on-error="handleError"
:on-exceed="handleExceed"
:on-progress="handleProgress"
:class="imageList.length >= maxCount ? 'uploaded-none':''"
:limit="maxCount"
>
<div class="icon-container" v-loading="loading">
<i class="el-icon-plus upload-icon"></i>
</div>
</el-upload>
</el-row>
<!-- 上传描述 -->
<el-row v-if="needDesc">
<div class="upload-text-desc" :style="descStyle">{{uploadDesc}}</div>
</el-row>
</div>
<!-- 🚀🚀🚀 查看图片 -->
<el-dialog
width="50%"
:modal="modal"
@close="imageVisible=false"
:modal-append-to-body="false"
:visible.sync="imageVisible"
>
<img width="100%" :src="dialogImageUrl" alt />
</el-dialog>
</div>
</template>
<script>
import { getBaseUrl, uuid as getUUId } from '@/utils/basic/' // 🚀 引入项目的api前缀
import { getToken } from '@/utils/browser' // 🚀 引入token
import { compress } from '@/utils/image/compress' // 🚀 引入上一步封装的压缩函数
import lodash from 'lodash'
export default {
name: 'UploadImage',
props: {
modal: { type: Boolean, default: () => { false } },
maxCount: { type: Number, required: true },
uploadDesc: { type: String },
initShowImages: { type: [Array, String], required: true },
singleFile: { type: Boolean, default: false },
needDesc: { type: Boolean, default: true },
handleChange: { type: Function, required: true },
descStyle: { type: Object, default: () => { null } }
},
data() {
return {
uploadUrl: getBaseUrl() + '/api/base/uploadImg',
token: { Authorization: getToken(), 'X-Trace-ID': getUUId() },
imageList: [],
loading: false,
imageVisible: false,
dialogImageUrl: ''
}
},
methods: {
// 启用压缩
resize(file, fileList) {
compress(file, fileList, this, this.$refs.imageUploadRef)
},
// 上传成功
handleSuccess(res, f, fList) {
if (res.status === 1 && res.result.length > 0) {
if (res.result[0].url) {
this.imageList.push({
url: res.result[0].url,
// 兼容saas的初始 attachmentUrl 属性
attachmentUrl: res.result[0].url // ❤❤❤
})
} else {
this.imageList.push({
url: fList[0].url,
// 兼容saas的初始 attachmentUrl 属性
attachmentUrl: fList[0].url // ❤❤❤
})
}
}
// 根据接收类型将结果发送到父组件
if (this.singleFile == true) {
this.handleChange(this.imageList[0].url)
} else {
this.handleChange(this.imageList)
}
this.loading = false
},
// 删除事件
handleRemove(res) {
this.imageList = lodash.filter(this.imageList, item => {
if (res.response) {
return item.url !== res.response.result[0].url
} else {
return item.url !== res.url
}
})
// 根据接收类型将结果发送到父组件 => 单个文件
if (this.singleFile == true) {
this.handleChange('')
} else {
this.handleChange(this.imageList)
}
this.$forceUpdate()
},
// 最大数
handleExceed() {
this.$message({ type: 'warning', message: `最多上传${this.maxCount}张图片` })
},
// 上传错误
handleError(err, file, fileList) {
this.$message({ message: err.data.msg, type: 'error' })
},
// 查看图片
handlePreview(file) {
this.dialogImageUrl = file.url
this.imageVisible = true
},
handleProgress() {
this.loading = true
}
},
mounted() {
// case: string(logo)
if (this.singleFile == true) {
// 非空值
if (this.initShowImages) {
this.imageList.push({ url: this.initShowImages })
} else {
this.imageList = []
}
} else {
// 列表文件
this.imageList = this.initShowImages
}
},
watch: {
initShowImages(val) {
// case: string(logo)
if (this.singleFile == true) {
// 非空值
if (val) {
this.imageList = [{ url: val }]
} else {
this.imageList = []
}
} else {
// 列表文件
this.imageList = val
}
}
}
}
</script>
<style lang="scss">
.upload-component-container {
.upload-section {
background: #ffffff;
border-radius: 4px;
padding-top: 2px;
.uploaded-none {
.el-upload--picture-card {
display: none;
}
}
.el-upload-list--picture-card .el-upload-list__item {
width: 60px;
height: 60px;
}
.el-upload--picture-card {
width: 60px;
height: 60px;
line-height: 125px;
i {
font-size: 20px !important;
}
}
.icon-container {
line-height: 2.5em;
padding-top: 12px;
}
.el-icon-plus:before {
// background: rgb(77, 227, 193);
color: #000;
border-radius: 12px;
}
}
.upload-text-desc {
font-size: 12px;
color: #939393;
margin-top: 4px;
margin-bottom: 5px;
}
}
</style>
在 vue 文件中使用
<template>
<div class="contract-other-edit-container">
<el-row>
<el-col :span="12">
<upload-image
:modal="false"
:maxCount="5"
uploadDesc="格式要求:支持jpg/jpeg/bmp/gif/png格式图片,大小不超过20MB,多上传5张图片."
:handleChange="handleUploadImage"
:initShowImages="imageList"
/>
</el-col>
</el-row>
</div>
</template>
<script>
import UploadImage from '@/components/element-ui/upload/image' // 组件的位置
export default {
name: 'other-edit',
components: { UploadImage },
data() {
return {
imageList: []
}
},
methods: {
handleUploadImage(files) {
this.imageList = files
}
}
}
</script>
Keep learning