业务场景与痛点
在开发分销或“邀请有礼”H5 活动时,传统方案通常由后端生成海报图片。在高并发场景下,这会带来巨大的服务器压力。
本文分享一套纯前端解决方案:后端仅返回邀请链接字符串,不生成二维码图片、不合成海报。所有逻辑(二维码生成、海报拼接、图片下载)均交由浏览器完成,实现动态海报的一键下载。
核心需求如下:
- 每个用户拥有专属邀请链接;
- 用户点击按钮即可生成带有个人二维码的活动海报;
- 海报可直接下载至手机并转发朋友圈;
- 后端零图片处理,显著降低服务器负载。
技术实现方案
采用原生 Canvas 结合 qrcodejs2 库,完全在客户端完成以下流程:
- 浏览器生成二维码;
- 前端进行海报背景与二维码的拼接;
- 触发浏览器下载功能;
- 后端仅需提供邀请 URL。
完整代码示例
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>邀请有礼海报</title>
<script src="https://cdn.jsdelivr.net/npm/qrcodejs2@0.0.2/qrcode.min.js"></script>
<style>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
padding: 20px;
text-align: center;
}
.download-btn {
padding: 14px 40px;
font-size: 18px;
background: #ff7823;
color: #fff;
border: none;
border-radius: 8px;
cursor: pointer;
margin-bottom: 20px;
}
</style>
</head>
<body>
<button class="download-btn" onclick="generateAndDownload()">生成并下载邀请海报</button>
<script>
const bgImgSrc = "/static/img/QQ20260906-192803.png";
const inviteUrl = "https://xxx.com/invite?uid=1001";
function loadImg(src) {
return new Promise(resolve => {
const img = new Image();
img.crossOrigin = "anonymous";
img.onload = () => resolve(img);
img.src = src;
})
}
function getQrCanvas(text, size) {
return new Promise(resolve => {
const tempDiv = document.createElement("div");
tempDiv.style.position = "absolute";
tempDiv.style.left = "-9999px";
document.body.appendChild(tempDiv);
new QRCode(tempDiv, {
text: text,
width: size,
height: size,
correctLevel: QRCode.CorrectLevel.H
});
setTimeout(() => {
const qrCanvas = tempDiv.querySelector("canvas");
document.body.removeChild(tempDiv);
resolve(qrCanvas);
}, 350);
})
}
async function generateAndDownload() {
try {
// 1、加载海报背景图
const bgImage = await loadImg(bgImgSrc);
// 2、生成二维码
const qrCanvas = await getQrCanvas(inviteUrl, 320);
const outCanvas = document.createElement("canvas");
outCanvas.width = 960;
outCanvas.height = 1282;
const ctx = outCanvas.getContext("2d");
// 绘制背景海报
ctx.drawImage(bgImage, 0, 0, 960, 1282);
// 二维码位置:水平居中,距离顶部 500px,和海报方框对齐
const qrSize = 320;
const qrX = (960 - qrSize) / 2;
const qrY = 500;
ctx.drawImage(qrCanvas, qrX, qrY, qrSize, qrSize);
// 浏览器下载图片
outCanvas.toBlob((blob) => {
if (!blob) return;
const a = document.createElement('a');
a.href = URL.createObjectURL(blob);
a.download = "邀请有礼.png";
a.click();
URL.revokeObjectURL(a.href);
}, "image/png");
} catch (e) {
console.error("海报生成失败:", e);
alert("海报生成失败,请检查图片路径,必须 http 服务访问,不要 file://打开");
}
}
</script>
</body>
</html>
开发与部署注意事项
运行环境要求
禁止直接双击 HTML 文件通过 file://协议打开,否则浏览器会因安全策略拦截 Canvas 导出操作。
正确做法:
- 本地开发:使用 VSCode Live Server 等插件启动本地 HTTP 服务;
- 线上部署:通过 Nginx 或 Apache 服务器,确保使用 http/https 协议访问。
尺寸与坐标调整
outCanvas.width/height:需与背景海报图片的实际宽高保持一致;qrX、qrY:控制二维码在海报上的具体位置,需根据设计模板进行微调。
海报背景示意
方案总结
该方案将图片计算完全移交至浏览器端,后端无需承担任何图片合成任务,接口仅需返回字符串链接。这种架构极大降低了服务器资源消耗,特别适用于高并发的邀请裂变活动场景。
关键词:海报合成、Canvas、qrcode、H5 开发

