使用 vue-upload 上传文件, 并进行压缩
<!-- 必须属性: visible, action, -->
<template>
<div class="upload-container">
<el-dialog v-loading="loading" :title="options.title" :visible.sync="options.visible" width="35%"
:before-close="beforeClose">
<el-row style="text-align: center; height: 0.3rem">
<b style="color: #f5222d;">上传完成前请勿关闭对话框</b>
</el-row>
<el-upload ref="fileUpload" drag :data="options.data" :headers="headers"
:multiple="true" list-type="picture" :file-list="fileList" :on-change="handleChange"
:auto-upload="false" :on-error="handleError"
:http-request="uploadFiles"
:on-exceed="handleExceed" :limit="options.limit" action="">
<i class="el-icon-upload"/>
<div class="el-upload__text">将文件拖到此处,或<em>点击上传</em></div>
<div class="el-upload__tip" slot="tip">只能上传图片文件,每个不超过5M, 一次最多上传{{options.limit}}个文件</div>
</el-upload>
<span slot="footer" class="dialog-footer">
<el-button @click="beforeClose">取 消</el-button>
<el-button type="primary" @click="submit()">确 定</el-button>
</span>
</el-dialog>
</div>
</template>
<script>
import {compress} from '@/utils/pictureUtils.js'
export default {
name: 'CustHouseFileUpload',
props: {
options: {
title: '上传附件',
visible: false,
url: 'basicdata/houseCustAccessory/custFileDocUpload',
//请求的额外参数
data: {},
limit: 5
}
},
data() {
return {
fileList: [],
loading: false,
headers: this.getHeaders(),
uploadSuccessFiles: [],
}
},
mounted() {
},
methods: {
//文件状态改变时的钩子,添加文件、上传成功和上传失败时都会被调用
handleChange(file, files) {
let temp = this.fileList.find(item => item.name === file.name);
if (temp && files.length > this.fileList.length) {
files.pop();
this.$notify.warning({
title: '提示',
message: '文件重复,请重新选择',
duration: 2000
});
return false;
}
this.fileList = [...files];
},
//文件超出个数限制时的钩子
handleExceed(files, fileList) {
this.$notify.warning({
title: '提示',
message: '以达到个数上限,请移除后再添加!',
duration: 2000
});
},
submit() {
//判断上传文件,没有文件给出友好提示
if (!this.fileList || !this.fileList.length) {
this.$notify.error({
title: '错误',
message: '请选择上传的文件',
duration: 2000
});
return;
}
this.fileList[0].status = 'ready';
// this.$refs.fileUpload.submit();
this.uploadFiles({file: this.fileList[0], data: this.options.data});
},
uploadFiles(param) {
let _this = this;
let formData = new FormData();
formData.append('data', JSON.stringify(param.data));
// 压缩后上传
this.compressAvatard(param.file, 1024 * 3, function (res) {
formData.append("files", res);
_this.uploadFileRequest(_this.options.url, formData, data => {
if (data && data.length > 0) {
_this.$notify({
title: '成功',
message: '上传成功',
type: 'success'
});
}
});
});
},
handleError(err, file, fileList) {
let errJson = JSON.stringify(err);
if (errJson && errJson.length > 50) {
errJson = "上传失败";
}
//上传失败处理
this.$notify.error({
title: '失败',
message: errJson,
duration: 3000
});
console.error(errJson, err);
},
beforeClose() {
this.fileList = [];
this.$refs.fileUpload.clearFiles();
this.uploadSuccessFiles = [];
this.options.visible = false;
//上传完成以后,调用父组件的方法进行刷新页面操作
this.$emit('closeFile');
},
getHeaders() {
return {
authorization: this.$store.getters["login/principal"],
token: this.$store.getters["login/token"],
uploadUserId: this.$store.getters["login/userId"],
}
},
//把图片文件作为参数传递到方法中
compressAvatard(file, kb, callback) {
let _this = this;
let raw = file.raw? file.raw: file;
compress(raw, function (val) {
// val是Blob类型,转换为file类型
let newfile = new window.File([val], file.name, {type: raw.type});
newfile.uid = file.uid;
// 压缩率过低则停止压缩, 防止死循环
if ((newfile.size / 1024) > kb && (newfile.size / file.size < 0.9 ) ) {
console.log("图片过大:" + newfile.size + ',已压缩');
_this.compressAvatard(newfile, kb, callback);
} else {
callback(newfile);
console.log("压缩后大小:" + newfile.size);
}
});
},
}
}
</script>
<style scoped>
.upload-container {
width: auto;
}
</style>
压缩工具类:
/**
* @日期 2020/12/9
* @描述:
*/
// 调用示例
// import { compress } from '@/utils/pictureUtils.js'
// if( (file.size/1024/1024) > 5){
// console.log("图片过大:" + file.size + ',已压缩');
// compress(file.raw, function(val){
// let newfile = new window.File([val], file.name, { type: file.raw.type });
// newfile.uid = file.uid;
// console.log("压缩后大小:" + newfile.size );
// });
// }
/** 图片压缩,默认同比例压缩
* @param {Object} fileObj
* 图片对象
* 回调函数有一个参数,base64的字符串数据
*/
export function compress(fileObj, callback) {
try {
const image = new Image();
image.src = URL.createObjectURL(fileObj);
image.onload = function() {
const that = this;
// 默认按比例压缩
let w = that.width;
let h = that.height;
const scale = w / h;
w = fileObj.width || w;
h = fileObj.height || (w / scale);
let quality = 0.8; // 默认图片质量为0.7
// 生成canvas
const canvas = document.createElement('canvas');
const ctx = canvas.getContext('2d');
// 创建属性节点
const anw = document.createAttribute('width');
anw.nodeValue = w;
const anh = document.createAttribute('height');
anh.nodeValue = h;
canvas.setAttributeNode(anw);
canvas.setAttributeNode(anh);
ctx.drawImage(that, 0, 0, w, h);
// 图像质量
if (fileObj.quality && fileObj.quality <= 1 && fileObj.quality > 0) {
quality = fileObj.quality
}
// quality值越小,所绘制出的图像越模糊
const data = canvas.toDataURL('image/jpeg', quality);
// 压缩完成执行回调
const newFile = convertBase64UrlToBlob(data);
callback(newFile)
}
} catch (e) {
console.error('压缩失败!', e)
}
}
function convertBase64UrlToBlob(urlData) {
const bytes = window.atob(urlData.split(',')[1]); // 去掉url的头,并转换为byte
// 处理异常,将ascii码小于0的转换为大于0
const ab = new ArrayBuffer(bytes.length);
const ia = new Uint8Array(ab);
for (let i = 0; i < bytes.length; i++) {
ia[i] = bytes.charCodeAt(i)
}
return new Blob([ab], { type: 'image/png' })
}