Layui结合JS实现前端图片压缩与上传方案

作者:资源驿站

时间:2026-10-23

浏览:195

本文介绍如何在Layui框架中利用JavaScript和Canvas实现前端图片压缩后上传。核心思路是将图片绘制到Canvas并调用toDataURL进行质量压缩,生成Blob对象。通过FormData修改文件字段或使用Ajax提交,解决自动上传时序问题,确保压缩生效。

文章目录

前端图片压缩原理与兼容性说明

关于前端JavaScript实现图片压缩的技术,网络上已有多种方案。本文基于现有方法进行了参考与修改,旨在提供一套可行的实现路径。


function photoCompress(file, w, objDiv) {
var ready = new FileReader();
/*开始读取指定的Blob对象或File对象中的内容. 当读取操作完成时,readyState属性的值会成为DONE,如果设置了onloadend事件处理程序,则调用之.同时,result属性中将包含一个data: URL格式的字符串以表示所读取文件的内容.*/
ready.readAsDataURL(file);
ready.onload = function() {
var re = this.result;
canvasDataURL(re, w, objDiv);
}
};
function canvasDataURL(path, obj, callback) {
var img = new Image();
img.src = path;
img.onload = function() {
var that = this;
// 默认按比例压缩
var w = that.width,
h = that.height,
scale = w / h;
w = obj.width || w;
h = obj.height || (w / scale);
var quality = 0.5; // 默认图片质量为0.7
//生成canvas
var canvas = document.createElement('canvas');
var ctx = canvas.getContext('2d');
// 创建属性节点
var anw = document.createAttribute("width");
anw.nodeValue = w;
var anh = document.createAttribute("height");
anh.nodeValue = h;
canvas.setAttributeNode(anw);
canvas.setAttributeNode(anh);
ctx.drawImage(that, 0, 0, w, h);
// 图像质量
if(obj.quality && obj.quality <= 1 && obj.quality > 0) {
quality = obj.quality;
}
// quality值越小,所绘制出的图像越模糊
var base64 = canvas.toDataURL('image/jpeg', quality);
// 回调函数返回base64的值
callback(base64);
}
}
function convertBase64UrlToBlob(urlData) {
var arr = urlData.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 Blob([u8arr], {
type: mime
});
}

图片压缩的核心逻辑是将原始图片数据绘制到Canvas元素中,随后利用Canvas的toDataURL方法对图像进行编码压缩,最终生成一个Blob对象以便后续处理。

需要注意的是,由于该方案依赖于Canvas API,低版本浏览器可能不支持此功能,具体兼容性需进一步验证。

掌握了图片压缩方法后,接下来需要解决如何将其集成到上传流程中,并发送至后端服务器。具体实现步骤如下。

基于Form表单的压缩上传实现

HTML结构部分如下:


<form action="file/uploadDoc" enctype="multipart/form-data" method="post" id="form">
<input type="file" id="file" name="file" />
<input type="submit" value="上传" />
</form>

JavaScript逻辑部分如下:


$("#file").change(function() {
var formData = new formData("form");
var file = this.files[0];
photoCompress(file, {
quality: 0.5,
}, function(base64Codes) {
var bl = convertBase64UrlToBlob(base64Codes);
formData.set("file", bl, file.name);
});
});

当用户选择文件后,调用photoCompress方法对图片进行压缩。该方法支持传入长宽等参数,具体配置可参考photoCompress函数的定义。其中quality参数用于控制压缩后的图片质量,数值越小,图片越模糊,但文件体积也越小。

最后,使用formData.set(key, value, name)方法更新表单中名为file的字段值。该函数包含三个参数:第一个参数key为表单元素的name属性值(若不存在则自动创建);第二个参数value为要设置的数据;第三个参数name为可选的文件名,当value为Blob或File对象时,此参数指定文件名。

基于Ajax的异步压缩上传方案

如果希望避免使用传统的Form表单提交,也可以采用Ajax异步提交的方式。

对应的HTML结构略有调整:


<form enctype="multipart/form-data" method="post" id="form">
<input type="file" id="file" name="file" />
<input type="button" value="上传" id="uploadBtn"/>
</form>

主要变化在于移除了Form的action属性,并将上传按钮的类型由submit改为button。

JavaScript部分为按钮绑定点击事件,其余逻辑保持不变,此处不再赘述:


$("#uploadBtn").click(function () {
var formData = new formData("form");
$.ajax({
type:"post",
url:"",
async:true,
data:formData,
success:function (data) {
},
error:function (e) {
}
});
});

Layui集成中的常见问题与解决方案

结合Layui组件使用时,遇到了一些常见问题及相应的解决方案。

首先查看HTML部分的实现:


<button type="button" class="layui-btn" id="upImg">上传图片</button>
<div id="img_list">
</div>
<input type="button" id = "btnHide" class="none">

代码结构较为简洁。此处额外添加了一个隐藏按钮,后续将解释其作用。

JavaScript逻辑部分如下:


layui.use('upload', function() {
var upload = layui.upload;
var uploadInst = upload.render({
elem: '#upImg',
url: '/upload/',
auto: false,
bindAction: "#btnHide",
choose: function(obj) {
var files = obj.pushFile();
var index, file, indexArr = [];
for(index in files) {
indexArr.push(index);
};
var iaLen = indexArr.length;
file = files[indexArr[iaLen - 1]];
for(var i = 0; i < iaLen - 1; i++) {
delete files[indexArr[i]];
}
try {
if(file.size > 200 * 1024) {
delete files[index];
photoCompress(file, {
quality: 0.5,
}, function(base64Codes) {
var bl = convertBase64UrlToBlob(base64Codes);
obj.resetFile(index, bl, file.name);
$("#btnHide").trigger("click");
});
} else {
$("#btnHide").trigger("click");
}
} catch(e) {
$("#btnHide").trigger("click");
}
},
done: function(res) {
//这里把后台返回的数据进行操作,展示上传完成的图片,具体数据格式参考layui的API
},
error: function() {
}
});
});

实现原理为:在用户选择照片后,获取文件对象并转换为Blob对象,通过resetFile方法重新设置文件队列,随后手动触发上传事件。

在开发过程中遇到了一些坑,具体说明如下:

第一,resetFile方法是Layui 2.3.0版本新增的功能,因此必须确保项目中使用的Layui版本为最新或至少不低于该版本。

第二,将auto参数设置为false以禁用自动上传,改为点击btnHide时触发上传。虽然尝试过自动上传模式,并将相关代码写入before回调中,但发现自动上传时修改文件队列的操作总是在上传成功后才执行,导致实际上传的仍是未压缩的原图。推测原因可能是图片转码及放入Canvas的过程耗时较长,影响了执行顺序。因此,最终采用手动上传方式,确保先修改文件队列,再手动触发上传。

第三,关于文件队列的处理。多次上传文件时,obj.pushFile()返回的文件对象key为随机字符串。因此,策略是每次上传完成后,使用delete方法删除队列中已处理的文件。不直接清空整个队列是因为考虑到无需压缩的情况,若直接清空且未执行resetFile,队列中将无文件,从而引发报错。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持本站。

实用工具推荐

电子包浆

绿化、压缩、噪点和虚拟水印,自由调节做旧程度。

使用 ›
图片压缩

选择画质和输出格式,预览压缩前后的大小。

使用 ›
相关文章