先说背景:工做中遇到一个问题,file组件上传图片,file是能够上传n张图片;可是,后台逻辑历史缘由,只能展示一张。所以:考虑到成本,决定在前端将多张图片合并成一张给后端。前端
_mergeImage2Canvas:function() { // 获取file上传和展示的图片。通常file上传以后,有个小图标展示。 var imgs = $(".img_files"); if (!imgs) { return false; } // 建立原始图像 // 缘由:file上传以后,展示每每是个缩略图,没法取到真正大小 for (var i = 0; i < imgs.length; i++) { var fbwImg = document.createElement("img"); var fbwImgID = "temp_img_id" + i; $("#" + fbwImgID).remove(); fbwImg.src = imgs[i].src; fbwImg.className = "temp-img-class"; // 不显示,仅供调用 fbwImg.style.display = "none"; // 临时区域扩展 $("#temp_section").append(fbwImg); } // 合并原始图片,生成一个新的base64 图片 var getOriginImgBase64 = function (oriImgs) { if (!oriImgs) { return false; } // 获取canvas的宽高 // 缘由:canvas须要首先指定宽高,因此须要提早获取最终的宽高 var maxWidth = 0; var height = 0; for (var i = 0; i < oriImgs.length; i++) { var img = oriImgs[i]; if (img.width > maxWidth) { maxWidth = img.width; } height += img.height; } // 设定canvas var canvas = document.createElement("canvas"); canvas.width = maxWidth + 10; canvas.height = height + 10; var ctx = canvas.getContext("2d"); // 留5margin var dheight = 5; for (var j = 0; j < oriImgs.length; j++) { var img = oriImgs[j]; var cheight = img.height; var cwidth = img.width; // 留5 margin ctx.drawImage(img, 5, dheight, cwidth, cheight); dheight = dheight + cheight + 5; } // 生成的base64 放在须要的一个全局变量中。 fbw_img_data = canvas.toDataURL('image/png'); // 清理 $(".temp_img_class").remove(); }; // 之因此使用timer,考虑到dom树若是没有加载完成,会取到高度有偏差 var imgTimer = null; imgTimer = setTimeout(function () { getOriginImgBase64($(".temp_img_class")); if (imgTimer) { clearTimeout(imgTimer); } }, 300); }
图片一:小站logocanvas
合成效果:app
主要是经过canvas 获取多个图片的base64编码,以后经过drawImage 函数合并和toDataUrl的方式合成。dom
问题一:必须支持canvas,不然还须要后台统一跑脚本处理。函数
问题二:性能消耗过大。append img 和base64代码对dom的消耗都挺大,尤为是在移动端,很容易形成崩溃。解决办法:设定最大宽度,将图片等比缩放,这样子就少了向dom扩展元素这部分的损耗。性能
问题三:base64 在传输上性能消耗也挺大,没有file原生的好。ui
所以:出了必须前端搞定,最好的方式,仍是在后台跑脚本运行合并。编码
我的小站原文连接 spa