文章目录
前言
uniapp 编译支付宝小程序canvas 合成图片实例,支付宝小程序 canvas 渲染图片 可以换成自己的图片即可
一、在页面中使用 Canvas
html
<template>
<view>
<!-- Canvas 画布 -->
<canvas
type="2d"
:id="alipayCanvasId"
:style="canvasStyle"
:width="canvasWidth" :height="canvasHeight"
@ready="onCanvasReady"
/>
<!-- 生成的海报预览 -->
<image
v-if="finalPosterUrl"
:src="finalPosterUrl"
mode="widthFix"
style="width: 100%; margin-top: 20rpx"
show-menu-by-longpress="true"
/>
</view>
</template>
二、在页面的 JS 文件中绘制图片
你可以使用 myCanvas 这个 canvas-id 来获取 canvas 上下文,并绘制图片。
javascript
<script>
export default {
data() {
return {
finalPosterUrl: '', // 生成的海报临时路径
alipayCanvasId:"alipayPosterCanvas",
alipayCanvas: null, // Canvas 实例
alipayCtx: null, // 2D 上下文
dpr: 1, // 设备像素比
// Canvas 基础配置
canvasWidth: 0, // 动态计算的canvas宽度
canvasHeight: 0, // 动态计算的canvas高度
canvasStyle: "", // canvas样式
};
},
methods: {
/**
* Canvas 就绪回调
*/
onCanvasReady() {
// 图片资源
const mainImgUrl = 'xxxxxx/haibao_image.png';
const qrImgUrl = 'xxxxxx/0379ec3faccad8485f136bd94b1486e1e367ac8c.jpeg';
// 查询 Canvas 节点
uni.createSelectorQuery()
// 绑定当前组件上下文(关键)
.select(`#${this.alipayCanvasId}`)
.node()
.exec(async (res) => {
if (!res || !res[0] || !res[0].node) {
console.error('未找到 Canvas 节点');
return;
}
// 初始化 Canvas 环境
this.initCanvasEnv(res[0].node);
try {
// 分步加载并绘制图片(使用封装的方法)
const mainImg = await this.loadImage(mainImgUrl);
this.drawMainImage(mainImg);
const qrImg = await this.loadImage(qrImgUrl);
this.drawQrCode(qrImg);
// 转换为临时图片
this.convertToTempImage();
} catch (err) {
console.error('海报生成失败:', err);
uni.showToast({ title: '生成失败', icon: 'none' });
}
});
},
/**
* 初始化 Canvas 环境(尺寸、上下文等)
*/
initCanvasEnv(canvasNode) {
this.alipayCanvas = canvasNode;
this.alipayCtx = canvasNode.getContext('2d');
// 获取设备信息
const sysInfo = uni.getSystemInfoSync();
this.dpr = sysInfo.pixelRatio || 1;
// 计算逻辑宽高(750rpx = 屏幕宽度)
this.canvasWidth = sysInfo.screenWidth;
this.canvasHeight = (1200 / 750) * sysInfo.screenWidth;
// 设置实际像素尺寸(解决模糊问题)
this.alipayCanvas.width = this.canvasWidth * this.dpr;
this.alipayCanvas.height = this.canvasHeight * this.dpr;
// 缩放上下文
this.alipayCtx.scale(this.dpr, this.dpr);
},
/**
* 封装:加载图片(支持网络图片下载 + Canvas 图片对象转换)
* @param {String} url - 图片URL
* @returns {Promise} - 加载完成的图片对象
*/
loadImage(url) {
return new Promise(async (resolve, reject) => {
try {
// 1. 下载网络图片(支付宝需要先下载为本地临时路径)
const tempPath = await this.downloadImage(url);
// 2. 将临时路径转换为 Canvas 可绘制的图片对象
const img = this.alipayCanvas.createImage();
img.onload = () => resolve(img);
img.onerror = () => reject(new Error(`图片加载失败: ${url}`));
img.src = tempPath; // 使用下载后的临时路径
} catch (err) {
reject(err);
}
});
},
/**
* 封装:下载网络图片为本地临时路径
* @param {String} url - 图片URL
* @returns {Promise} - 本地临时路径
*/
downloadImage(url) {
return new Promise((resolve, reject) => {
// 校验URL有效性
if (!url || typeof url !== 'string') {
reject(new Error(`无效的图片URL: ${url}`));
return;
}
uni.downloadFile({
url,
success: (res) => {
if (res.statusCode === 200) {
resolve(res.tempFilePath); // 返回临时路径
} else {
reject(new Error(`下载失败,状态码: ${res.statusCode}`));
}
},
fail: (err) => {
reject(new Error(`下载错误: ${err.errMsg}`));
}
});
});
},
/**
* 绘制主图
* @param {Object} img - 主图图片对象
*/
drawMainImage(img) {
// 铺满整个画布
this.alipayCtx.drawImage(img, 0, 0, this.canvasWidth, this.canvasHeight);
},
/**
* 绘制二维码
* @param {Object} img - 二维码图片对象
*/
drawQrCode(img) {
// 二维码尺寸(画布宽度的30%)
const qrSize = this.canvasWidth * 0.3;
// 二维码位置(底部居中,距离底部20rpx)
const qrX = (this.canvasWidth - qrSize) / 2;
const qrY = this.canvasHeight - qrSize - (20 / 750) * this.canvasWidth;
// 绘制白色背景(增强对比度)
this.alipayCtx.fillStyle = '#ffffff';
this.alipayCtx.fillRect(qrX - 10, qrY - 10, qrSize + 20, qrSize + 20);
// 绘制二维码
this.alipayCtx.drawImage(img, qrX, qrY, qrSize, qrSize);
},
/**
* 转换 Canvas 为临时图片
*/
convertToTempImage() {
uni.canvasToTempFilePath({
canvasId: this.alipayCanvasId,
width: this.canvasWidth,
height: this.canvasHeight,
destWidth: this.canvasWidth * this.dpr, // 输出高清图
destHeight: this.canvasHeight * this.dpr,
success: (res) => {
this.finalPosterUrl = res.tempFilePath;
console.log('海报生成成功:', res.tempFilePath);
},
fail: (err) => {
console.error('转换图片失败:', err);
uni.showToast({ title: '转换失败', icon: 'none' });
}
}, this);
}
}
};
</script>
总结
注意事项
跨域问题:如果图片 URL 是外部链接,确保服务器支持跨域请求,或者在支付宝小程序管理后台添加图片的域名到"业务域名"白名单中。
图片加载:由于网络请求和图片加载可能需要时间,建议在 onReady 或在图片加载成功后调用 drawImage 方法。
动态图片:如果图片是动态生成的或者来自用户上传,确保在调用 drawImage 前图片已经加载完成。可以使用 my.getImageInfo 方法获取图片信息,例如尺寸等,然后再进行绘制。