uniapp微信小程序分享封面自定义
·
使用canvas进行绘制
// 合成后的分享图临时路径
const shareImgUrl = ref('');
// 图标
const STATIC_USER = '/static/images/shareImg/user.png';
const assetUserPath = ref('');
// 绘制图片到画布(通用函数)
const drawImageToCanvas = async (canvas, ctx, imgSrc, x, y, width, height) => {
return new Promise((resolve, reject) => {
if (!imgSrc) {
reject(new Error('图片路径为空'));
return;
}
const img = canvas.createImage();
img.src = imgSrc;
img.onload = () => {
ctx.drawImage(img, x, y, width, height);
resolve(img);
};
img.onerror = (err) => {
console.error(`图片加载失败: ${imgSrc}`, err);
reject(err);
};
});
};
// 缓存,避免每次打开都重新下载图片(能显著减少 4~5s 等待)
const imagePathCache = new Map();
const resolveLocalImagePath = (src) => {
if (imagePathCache.has(src)) return imagePathCache.get(src);
const p = new Promise((resolve) => {
if (!src) return resolve('');
const isAbsoluteLike =
src.startsWith('/') ||
src.startsWith('https') ||
src.startsWith('wxfile://') ||
src.startsWith('file://') ||
src.startsWith('data:');
const normalizedSrc = isAbsoluteLike ? src : `/${src}`;
uni.getImageInfo({
src: normalizedSrc,
success: (res) => {
const p = res?.path || normalizedSrc;
resolve(p.startsWith('static/') ? `/${p}` : p);
},
fail: () => resolve(normalizedSrc),
});
});
imagePathCache.set(src, p);
return p;
};
// 通用函数
const setAssetPath = async (r, p) => !r.value && (r.value = await resolveLocalImagePath(p))
// 绘制分享卡片
const createShareImg = async () => {
try {
// 并行执行,速度更快
await Promise.all([
[assetUserPath, STATIC_USER],
].map(([ref, path]) => setAssetPath(ref, path)))
// 1. 获取活动信息
const activityInfo = getActivityInfo();
// 2. 查询 Canvas 节点(Vue 3 script setup 中不需要 .in(this))
const query = uni.createSelectorQuery();
const res = await new Promise(resolve => {
query.select('#shareCanvas')
.fields({ node: true, size: true })
.exec(resolve);
});
if (!res[0]?.node) {
console.error('Canvas 节点获取失败');
return;
}
const canvas = res[0].node;
const ctx = canvas.getContext('2d');
// 从基础库 2.20.1 开始,本接口停止维护,建议使用 uni.getWindowInfo() 获取窗口信息
// const dpr = uni.getSystemInfoSync().pixelRatio;
const dpr = uni.getWindowInfo().pixelRatio;
// 3. 设置画布分辨率(5:4)
canvas.width = 500 * dpr;
canvas.height = 400 * dpr;
ctx.scale(dpr, dpr);
// 4. 绘制背景图
try {
// 参数从左到右说明, 图片文件,x轴开始位置,y轴开始位置,x轴结束位置,y轴结束位置
await drawImageToCanvas(canvas, ctx, activityInfo.bgImg, 0, 0, 500, 400);
} catch (e) {
console.warn('背景图加载失败,使用默认图占位:', e.message);
await drawImageToCanvas(canvas, ctx, assetDefaultBgPath.value, 0, 0, 500, 400);
}
// 5. 绘制绿色边框(模拟卡片效果)
if (assetBorderPath.value) {
try {
// 参数从左到右说明, 图片文件,x轴开始位置,y轴开始位置,x轴结束位置,y轴结束位置
await drawImageToCanvas(canvas, ctx, assetBorderPath.value, 0, 0, 500, 400);
} catch (e) {
console.warn('边框绘制失败:', e.message);
}
}
// 7. 绘制右上角红色价格标签
if (activityInfo.price) {
try {
// 参数从左到右说明, 图片文件,x轴开始位置,y轴开始位置,x轴结束位置,y轴结束位置
await drawImageToCanvas(canvas, ctx, assetLabelPath.value, 390, 1, 69, 80);
}catch(e){
console.warn('价格标签背景绘制失败:', e.message);
}
ctx.fillStyle = '#fff';
ctx.font = '15px sans-serif';
ctx.textAlign = 'center';
ctx.fillText(activityInfo.priceTagText, 427, 25);
ctx.fillText('¥', 406, 57);
ctx.font = 'bold 22px sans-serif';
ctx.fillText(activityInfo.price, 430, 57);
}
// 8. 绘制底部信息栏背景
if (assetJianbianPath.value) {
try {
await drawImageToCanvas(canvas, ctx, assetJianbianPath.value, 0, 270, 500, 130);
} catch (e) {
console.warn('底部信息背景绘制失败:', e.message);
}
}
// 9. 绘制报名信息、时间、地址图标和文字
ctx.fillStyle = '#fff';
ctx.font = '20px sans-serif';
ctx.textAlign = 'left';
// 报名信息
if (activityInfo.participant) {
try {
await drawImageToCanvas(canvas, ctx, assetUserPath.value, 23, 295, 17, 17);
} catch (e) {
console.warn('报名图标加载失败:', e.message);
}
ctx.fillText(activityInfo.participant, 50, 310);
}
// 时间
if (activityInfo.time) {
try {
await drawImageToCanvas(canvas, ctx, assetTimePath.value, 23, 330, 17, 17);
} catch (e) {
console.warn('时间图标加载失败:', e.message);
}
ctx.fillText(`时间:${activityInfo.time}`, 50, 345);
}
// 地址
if (activityInfo.address) {
try {
await drawImageToCanvas(canvas, ctx, assetAddressPath.value, 23, 365, 17, 17);
} catch (e) {
console.warn('地址图标加载失败:', e.message);
}
ctx.fillText(`地址:${(activityInfo.address || '').slice(0,19)} ${(activityInfo.address || '').length>19 ? '...' : ''}`, 50, 380);
}
// 10. 转成临时图片
uni.canvasToTempFilePath({
canvas: canvas,
width: 500,
height: 400,
success: (res) => {
shareImgUrl.value = res.tempFilePath;
console.log('分享卡片生成成功:', shareImgUrl.value);
},
fail: (err) => {
console.error('生成分享卡片失败:', err);
}
});
} catch (err) {
console.error('createShareImg 异常:', err);
}
}
// 分享给好友
onShareAppMessage(() => {
const detail = activityDetail.value;
return {
// 标题不切割,微信限制最多展示两行
title: `${formatStartDate.value} | ${detail.activityName}` || '精彩活动等你来',
path: `/pages/active/ActivityDetail?id=${contentId.value}`,
imageUrl: shareImgUrl.value
};
});
更多推荐
所有评论(0)