注意事项:未解决PNG带通道透明图片压缩后黑屏的问题,网上有评论说绘制背景色白色
context.fillStyle = '#fff'
个人觉得意义不大,因为只要是做设计的都明白透明通道和白色背景不是同一个概念。
为啥不支持PNG?
点击此处查看原因
原因总结:会用到toDataURL('image/jpeg',qualitys)的一个方法
在指定图片格式为 image/jpeg 或 image/webp的情况下,可以从 0 到 1 的区间内选择图片的质量。如果超出取值范围,将会使用默认值 0.92,其他参数会被忽略。
文件工具:compress.js
export default {
compressImg: function(file, quality) {
var qualitys = 0.52
// console.log(parseInt((file.size / 1024).toFixed(2)))
if (parseInt((file.size / 1024).toFixed(2)) < 1024) {
qualitys = 0.85
}
if (5 * 1024 < parseInt((file.size / 1024).toFixed(2))) {
qualitys = 0.92
}
if (quality) {
qualitys = quality
}
if (file[0]) {
return Promise.all(
Array.from(file).map(e => this.compressImg(e, qualitys))
) // 如果是 file 数组返回 Promise 数组
} else {
return new Promise(resolve => {
// console.log(file)
if ((file.size / 1024).toFixed(2) < 300) {
resolve({
file: file
})
} else {
const reader = new FileReader() // 创建 FileReader
reader.onload = ({ target: { result: src } }) => {
const image = new Image() // 创建 img 元素
image.onload = async () => {
const canvas = document.createElement('canvas') // 创建 canvas 元素
const context = canvas.getContext('2d')
var targetWidth = image.width
var targetHeight = image.height
var originWidth = image.width
var originHeight = image.height
if (
1 * 1024 <= parseInt((file.size / 1024).toFixed(2)) &&
parseInt((file.size / 1024).toFixed(2)) <= 10 * 1024
) {
var maxWidth = 1600
var maxHeight = 1600
targetWidth = originWidth
targetHeight = originHeight
// 图片尺寸超过的限制
if (originWidth > maxWidth || originHeight > maxHeight) {
if (originWidth / originHeight > maxWidth / maxHeight) {
// 更宽,按照宽度限定尺寸
targetWidth = maxWidth
targetHeight = Math.round(
maxWidth * (originHeight / originWidth)
)
} else {
targetHeight = maxHeight
targetWidth = Math.round(
maxHeight * (originWidth / originHeight)
)
}
}
}
if (
10 * 1024 <= parseInt((file.size / 1024).toFixed(2)) &&
parseInt((file.size / 1024).toFixed(2)) <= 20 * 1024
) {
maxWidth = 1400
maxHeight = 1400
targetWidth = originWidth
targetHeight = originHeight
// 图片尺寸超过的限制
if (originWidth > maxWidth || originHeight > maxHeight) {
if (originWidth / originHeight > maxWidth / maxHeight) {
// 更宽,按照宽度限定尺寸
targetWidth = maxWidth
targetHeight = Math.round(
maxWidth * (originHeight / originWidth)
)
} else {
targetHeight = maxHeight
targetWidth = Math.round(
maxHeight * (originWidth / originHeight)
)
}
}
}
canvas.width = targetWidth
canvas.height = targetHeight
context.clearRect(0, 0, targetWidth, targetHeight)
context.fillStyle = '#fff'
context.drawImage(image, 0, 0, targetWidth, targetHeight) // 绘制 canvas
const canvasURL = canvas.toDataURL('image/jpeg', qualitys)
const buffer = atob(canvasURL.split(',')[1])
let length = buffer.length
const bufferArray = new Uint8Array(new ArrayBuffer(length))
while (length--) {
bufferArray[length] = buffer.charCodeAt(length)
}
const miniFile = new File([bufferArray], file.name, {
type: 'image/jpeg'
})
console.log({
file: miniFile,
origin: file,
beforeSrc: src,
afterSrc: canvasURL,
beforeKB: Number((file.size / 1024).toFixed(2)),
afterKB: Number((miniFile.size / 1024).toFixed(2)),
qualitys: qualitys
})
resolve({
file: miniFile,
origin: file,
beforeSrc: src,
afterSrc: canvasURL,
beforeKB: Number((file.size / 1024).toFixed(2)),
afterKB: Number((miniFile.size / 1024).toFixed(2))
})
}
image.src = src
}
reader.readAsDataURL(file)
}
})
}
}
}
上述工具返回的是一个promise对象.
在你封装好的的uploader.vue组件中使用
import Compress from '@/utilities/compress.js'
关键点:因为异步的原因,我们无法在elementui 上传组件的 beforeUpload()方法中使用,必须使用自定义的方法上传,覆盖掉组件的上传方法
<template>
<div class="container">
<el-upload :multiple="multiple" :accept="types.join(',')" :show-file-list="showFileList" :action="$root.settings.DOMAIN_APIS.Violet + '/security/upload/temporary'" :data="{ cloud: 'violet', micro: micro}" :headers="{'access-token': $store.getters.access_token,}" :before-upload="beforeUpload" :on-success="onSuccess" :on-error="onError" :on-remove="onRemove">
<el-button>
<i class="el-icon-upload"></i>
{{btnText}}
</el-button>
</el-upload>
<div class="customFileList" v-if="!showFileList">
<p v-for="(item,index) in fileList" :key=index class="fileList">
<a :href="$root.settings.DOMAIN_IMG_FILE+item.Url" target="_blank">{{item.Name}}</a>
<i class="el-icon-delete" @click="deleteButton(item.url)"></i>
</p>
</div>
</div>
</template>
<script>
import {OSS_URL} from '@/apis/violet'
// :http-request="uploadSectionFile"
import Compress from '@/utilities/compress.js'
export default {
props: {
// 是否使用ui框架上传列表,默认使用,但无预览功能
showFileList: {
type: Boolean,
default: true
},
fileList: {
type: Array,
default: () => ([])
},
types: {
// 文件类型,默认图片jpeg,jpg,png
type: Array,
default: () => (['image/jpeg', 'image/jpg', 'image/png'])
},
multiple: {
type: Boolean,
default: false
},
micro: {
// 上传目录
type: String,
default: 'security'
},
fileSize: {
// 文件大小限制 单位MB
type: Number,
default: 2
},
btnText: {
type: String,
default: '上传文件'
}
},
data() {
return {
loading: false,
}
},
methods: {
uploadFile(copyFile){
console.log(copyFile)
},
uploadSectionFile(params) {
console.log(params)
const file = params.file,
fileType = file.type,
isImage = fileType.indexOf("image") != -1,
isLt2M = file.size / 1024 / 1024 < 20
// 这里常规检验,看项目需求而定
if (!isImage) {
this.$message.error("只能上传图片格式png、jpg、gif!");
return
}
if (!isLt2M) {
this.$message.error("只能上传图片大小小于2M");
return
}
// 真正要做压缩图片大小的地方
Compress.compressImg(file).then((res) => {
console.log(file)
const copyFile = res.file
imageUpload(copyFile)
})
const imageUpload = (copyFile) => {
const apiFoo = OSS_URL
let data={ cloud: 'violet', micro: this.micro,file:copyFile}
return apiFoo(data).then(res => {
if (res.data.Code === 'CORRECT') {
console.log(res)
}
})
}
this.loading=true
},
beforeUpload(file) {
if ((file.type && !this.types.includes(file.type)) || (!file.type && !this.types.includes(`.${file.name.split('.')[1]}`))) {
this.$message.error('请上传正确文件!')
return false
}
if (file.size / 1024 / 1024 > this.fileSize) {
this.$message.error(`文件大小不能超过${this.fileSize}MB!`)
return false
}
// 理论上在这个压缩图片大小,实际上beforeUpload没有用到,
// return new Promise((resolve, reject) => {
// Compress.compressImg(file).then((res) => {
// console.log(res.file)
// file = res.file
// console.log(file)
// // resolve()
// const copyFile = file
// this.uploadFile(copyFile)
// return false
// })
// })
this.loading = true
},
onSuccess(res, file) {
if (res.Code == 'CORRECT') {
this.getBase64Image(file.raw).then(result => {
res.Data.Subset.forEach(item => {
this.$emit('onSuccess', item.Rel, result, file)
})
})
} else {
this.$message.error(res.Message)
}
this.loading = false
},
onError() {
this.loading = false
this.$message.error('上传失败,请稍后重试!')
},
onRemove(file) {
if (file && file.status === 'success') {
this.$emit('onRemove', file.url)
}
},
getBase64Image(img) {
return new Promise((calback) => {
var reader = new FileReader()
reader.readAsDataURL(img) // 转化二进制流,异步方法
reader.onload = function () { // 完成后this.result为二进制流
calback(this.result)
}
})
},
deleteButton(url) {
this.$emit('onRemove', url)
}
}
}
</script>
<style lang="scss" scoped>
.upload-img {
position: relative;
border: 1px dashed $border-color;
box-sizing: content-box;
cursor: pointer;
&:hover {
border-color: $light-blue;
}
border-radius: 6px;
/deep/ .el-upload {
width: 100%;
height: 100%;
i {
display: inline-block;
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
color: #8c939d;
font-size: $middle-font;
}
img {
display: block;
width: 100%;
height: 100%;
}
}
/deep/ .el-loading-spinner {
margin-top: -25px;
}
}
/deep/ .fileList {
display: flex;
justify-content: space-between;
.el-icon-delete:hover {
cursor: pointer;
}
.el-icon-delete {
margin-right: 20px;
}
}
</style>
额外记录,与当前文章无关
// violet.js
export const OSS_URL = (parameters) => {
return fetch({
cloud: 'Violet',
url: '/security/upload/temporary',
method: 'post',
data: parameters,
})
}
//fetch.js
headers: {
'X-Requested-With': 'XMLHttpRequest',
// 'Content-Type': 'application/json; charset=utf-8',
'Content-Type': 'multipart/form-data; boundary=----WebKitFormBoundary5J9Z4y1jAznANNwp',
}
if (config.method === 'post') {
//config.data = JSON.stringify(config.data)
const formdata = new FormData()
formdata.append('cloud', 'violet'),
formdata.append('micro', 'agiles'),
formdata.append('file', config.data.file),
config.data=formdata
}
//demandAdd.vue
:fileSize=20
网友评论