项目场景:
项目需求循环文件上传前循环压缩至指定大小后再提交
解决方案:
file.js
export async function fileCompress(file, ms) {
var maxSize = 1024 * 1024; // 文件最大限制 默认1M
if (ms) { maxSize = ms * 1024 * 1024 }
var newFile = await compress(file, maxSize);
while (newFile.size / 1024 / 1024 >= ms) {
newFile = await compress(newFile, maxSize);
}
return newFile
}
function compress(file, maxSize) {
return new Promise((resolve, reject) => {
var newFile = file
if (file.size > maxSize) { // 如果图片大小大于1m,进行压缩
// console.log('进行压缩')
var da = file.size / maxSize
var w_h = 0.7 //宽高压缩比
var quality = 0.5
if (da >= 10) {
w_h = 0.3
quality = 0.2
}
if (da >= 2 && da < 10) {
w_h = 0.5
quality = 0.3
}
w_h = 1 //宽高不压缩了
// 看支持不支持FileReader
if (!file || !window.FileReader) return;
// 创建一个 Image 对象
var image = new Image();
// 绑定 load 事件处理器,加载完成后执行
image.onload = function () {
// 获取 canvas DOM 对象
var canvas = document.createElement('canvas')
// 返回一个用于在画布上绘图的环境, '2d' 指定了您想要在画布上绘制的类型
var ctx = canvas.getContext('2d')
image.width *= w_h; image.height *= w_h;
// 获取 canvas的 2d 环境对象,
ctx.clearRect(0, 0, canvas.width, canvas.height);// canvas清屏
canvas.width = image.width;// 重置canvas宽高
canvas.height = image.height;
ctx.drawImage(image, 0, 0, image.width, image.height);// 将图像绘制到canvas上
// !!! 注意,image 没有加入到 dom之中
var newSrc = canvas.toDataURL(file.type, { quality: quality });
newFile = base64ToFile(newSrc, file.name); // 转成file文件
// console.log('compress----')
return resolve(newFile);
};
if (/^image/.test(file.type)) {
// 创建一个reader
var reader = new FileReader();
// 将图片将转成 base64 格式
reader.readAsDataURL(file);
// 读取成功后的回调
reader.onload = function () {
// self.imgUrls.push(this.result);
// 设置src属性,浏览器会自动加载。
// 记住必须先绑定事件,才能设置src属性,否则会出同步问题。
image.src = this.result;
}
}
} else {
return resolve(newFile);
}
})
}
function base64ToFile(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 });
}
如何使用:
<template>
<div class="picUpload">
<a-upload
list-type="picture-card"
:file-list="fileList"
:customRequest="customRequest"
@preview="handlePreview"
:remove="removePic"
:multiple="false"
>
<div v-if="fileList.length < 1">
<a-icon type="plus" />
<div class="ant-upload-text">上传</div>
</div>
</a-upload>
<a-modal
wrapClassName="spcModal"
:closable="false"
:maskClosable="false"
v-model="previewVisible"
width="800px"
:footer="null">
<a-icon @click="handleCancel" class="close" type="close-circle"/>
<img v-if="type=='image'" alt="example" style="width: 100%" :src="previewFile.realurl" />
<video v-if="previewVisible&&type=='video'" style="width:100%;display: block;" controls autoplay :src="previewFile.realurl"/>
</a-modal>
</div>
</template>
<script>
import { fileCompress } from '@/utils/file.js'
export default {
name: 'SingleUpload',
props: {
value:{
type:String,
default:''
},
apiUrl: {
type: String,
default:'/basedata/v1.0/upload?type=31'
},
type:{
type:String,
default:'image' //video
}
},
data() {
return {
previewVisible: false,
previewFile: {},
fileList: []
}
},
mounted(){
this.valueDeal()
},
watch: {
value: {
immediate: true,
handler(newvalue, oldvalue) {
this.valueDeal()
}
}
},
methods: {
valueDeal(){
var url=this.httpCheck(this.value)
console.log(url)
if(url){
this.fileList = [{
url: this.type=='image'?url:(url+'?x-oss-process=video/snapshot,t_1000,f_jpg,w_50,h_50,m_fast'),
realurl:url,
uid: url,
name: 'file',
status: 'done'
}]
}else{
this.fileList=[]
}
},
httpCheck(url){
if(url){
if(url.indexOf('http') < 0){
return 'https://njcyy.oss-cn-beijing.aliyuncs.com/' + url;
}else{
return url
}
}else{
return ''
}
},
handleCancel() {
this.previewVisible = false
},
// 查看大图
handlePreview(file) {
if (file.status === 'done') {
this.previewFile = file
this.previewVisible = true
}else{
this.previewFile = {}
}
},
// 删除
removePic(file) {
this.fileList = []
this.$emit('input','')
return false
},
// 自定义上传
async customRequest(data) {
var filetype=data.file.type.split('/')[0]
if(filetype!=this.type){
this.$message.error('请上传正确的文件类型。')
return
}
const fileId = data.file.uid
const file = await fileCompress(data.file, 2)
const fileName = file.name
const formData = new FormData()
formData.append('file', file)
this.api.post(this.apiUrl, formData, {
headers: {
'Content-Type': 'multipart/form-data'
}
}).then(res => {
res=this.httpCheck(res)
this.fileList=[{
url: this.type=='image'?res:(res+'?x-oss-process=video/snapshot,t_1000,f_jpg,w_50,h_50,m_fast'),
realurl:res,
uid: fileId,
name: fileName,
status: 'done'
}]
this.$emit('input',res)
})
}
}
}
</script>
<style lang='less' scoped>
.picUpload {
height: 110px;
}
</style>