压缩方法参考:https://juejin.cn/post/6940430496128040967
大家可以持续关注我的系列优化文章
Wing主题优化记录
背景
wing主题默认说说的图片上传是原图上传到了wp的素材库,手机发布的时候一般选择随手拍的照片,得益手机越来越好的像素,原图都非常大,首页大图多了,会严重拖慢首页的加载速度,像我这个个人的小水管服务器根本受不了,效果如下,加载很影响体验
而我本身并没有在博客发布原图的诉求,所以得想个办法解决一下
前端压缩
本来想着可以在后端存储的时候压缩一下,存储一下多倍图,前端可以选择压缩后的图输出,想了一下我完全没有在博客存储原图的诉求,所以直接在前端上传前压缩吧,还能提升上传的速度
直接放代码:https://github.com/moxiaonai/Wing-magic/blob/main/static/modules.js#L295
/**
* 压缩图片方法
* @param {file} file 文件
* @param {Number} quality 图片质量(取值0-1之间默认0.92)
*/
compressImg(file, quality) {
var qualitys = 0.52
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) => {
if ((file.size / 1024).toFixed(2) < 300) {
resolve(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.drawImage(image, 0, 0, targetWidth, targetHeight) // 绘制 canvas
const extType = file.type
const canvasURL = canvas.toDataURL(extType, 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: extType
})
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(miniFile)
}
image.src = src
}
reader.readAsDataURL(file)
}
})
}
},
使用:
async handleUpload(e) {
const { files } = (e.target || {});
const len = { flag: 0, count: files.length };
this.uploading = true;
const imgs = await this.compressImg(files)
Array.from(imgs).forEach(file => {
const formData = new FormData();
formData.append("file", file);
file.id = Math.random().toString(32).substring(2);
this.files.push({ id: file?.id, source_url: file.name, loading: true });
$h.rest('wp/v2/media', {
method: 'POST',
headers: {
'Content-Type': null,
'Content-Disposition': `attachment; filename=${encodeURI(file.name)}`
},
body: formData,
}).then(({ id, guid, mime_type }) => {
if(id) {
// 根据id替换
this.files = this.files.map(item => {
if ( item.id === file.id ) {
item = { id, source_url: guid.raw, mime_type, loading: false };
}
return item;
});
}
}).finally(() => {
if ( ++len.flag === len.count ) {
this.uploading = false;
}
}).catch(err=>{
this.files.pop();
})
});
e.target.value = ""; // 清空input
},
可以根据需要调整quality,目前的参数是经过大佬调整多轮后的最优解了,原方案里面图片类型我做了调整,压缩图片继承原图片格式类型const extType = file.type
,如果需要统一转成png或者其他格式,这里可以设置为固定值
至此,体验终于好了很多!