点击分享按钮,将背景图、标题、二维码、介绍文字等内容合并生成为分享海报,需要通过canvas将所需元素重新拼接绘制为新的图片,具体代码如下:
html
需要建立一个canvas画布,并定义其canvas-id属性,以便后续使用
<template>
<view>
<canvas
class="myCanvas"
canvas-id="myCanvas"
:style="'width:' + posterWidth + 'px; height:' + posterHeight + 'px'"
></canvas>
</view>
</template>
js
- 首先,定义状态值,存储设备屏幕的宽高、海报宽高、图片url,并接收父组件传递的海报所需信息(图片、文字等)。
- 其次,使用uni.createCanvasContext(canvasId, this)创建画布ctx,这时就用到了canvas定义的canvas-id属性啦
-
为了更好地适配设备,我们通过uni.getSystemInfo 获取一下设备的宽高,并且结合ui设计图,确定海报的宽高
接下来,就要正式进行画图操作了!
-
定义绘制海报各个元素的方法
-
绘制背景 —— ctx.drawImage 绘制背景图,ctx.setFillStyle填充背景色,ctx.fillRect绘制矩形区域并填充指定的内容;
-
绘制二维码 —— 同样需要使用drawImage、setFillStyle、fillRect,另外由于此处ui设计有阴影,需要通过ctx.setShadow添加一下图片阴影【canvas绘制会根据绘制先后对绘制内容进行叠加,也就是后绘制的部分会自动位于画面图层顺序的最顶层,注意一下】
-
插入文字 —— ctx.setFillStyle和ctx.setFontSize先确定文字的样式,再通过ctx.fillText进行文字的创建
-
-
定义绘制海报并保存的方法
-
调用所定义的绘制各个元素的方法
-
通过ctx.draw进行绘制,并调用uni.canvasToTempFilePath(object, component),把当前画布指定区域的内容导出生成指定大小的图片,并通过成功的回调获取到返回的图片文件路径
-
一旦获取图片url,就可以通过uni.saveImageToPhotosAlbum(OBJECT),保存我们的海报图片到系统相册咯~
-
-
最最后,由于这里是vue3,因此记得要将子组件的方法通过defineExpose({ drawPoster })暴露出去,以供父组件调用,实现功能。
<script setup lang="ts">
const windowWidth = ref(0); // 设备屏幕宽度
const windowHeight = ref(0); // 设备屏幕高度
const posterWidth = ref(0); // 海报宽度
const posterHeight = ref(0); // 海报高度
const imgUrl = ref(""); // 最终生成的海报图片url
// 接收父组件传递的海报所需内容数据
const { posterData } = defineProps<{
posterData: any;
}>();
// 创建画布
const ctx = uni.createCanvasContext("myCanvas", this);
// 获取系统宽高
const getSystem = () => {
uni.getSystemInfo({
success: function (res) {
windowHeight.value = res.windowHeight;
windowWidth.value = res.windowWidth;
posterWidth.value = res.windowWidth * 0.8;
posterHeight.value = posterWidth.value * 1.375;
},
});
};
// 绘制背景图
const setBg = () => {
ctx.drawImage(
posterData.backgroundUrl,
0,
0,
posterWidth.value,
posterHeight.value
);
ctx.setFillStyle("#ffffff");
ctx.fillRect(
posterWidth.value * 0.1,
posterHeight.value * 0.8,
posterWidth.value * 0.8,
posterHeight.value * 0.15
);
ctx.save();
};
// 绘制二维码
const setQrcode = () => {
ctx.setFillStyle("#ffffff");
ctx.setShadow(0, 1, 10, "#FAD3AC");
ctx.fillRect(
posterWidth.value * 0.12,
posterHeight.value * 0.82,
posterWidth.value * 0.16,
posterWidth.value * 0.16
);
ctx.drawImage(
posterData.qrcode,
posterWidth.value * 0.12,
posterHeight.value * 0.82,
posterWidth.value * 0.16,
posterWidth.value * 0.16
);
ctx.save();
};
// 绘制文字
const setText = (text, color, size, x, y) => {
console.log("渲染文字", text);
ctx.save();
ctx.setFillStyle(color);
ctx.setFontSize(size);
ctx.fillText(text, x, y);
ctx.save();
};
// 绘制海报
const drawPoster = () => {
setBg();
setQrcode();
setText(
posterData.title,
"#666666",
10,
posterWidth.value * 0.36,
posterHeight.value * 0.86
);
setText(
posterData.context,
"#666666",
10,
posterWidth.value * 0.36,
posterHeight.value * 0.91
);
setTimeout(() => {
//必须延时执行 不然h5不显示
ctx.save();
ctx.draw(true, () => {
setTimeout(() => {
uni.canvasToTempFilePath(
{
canvasId: "myCanvas",
success: (res) => {
uni.showLoading({
title: "保存中...",
});
console.log(res.tempFilePath);
imgUrl.value = res.tempFilePath;
// #ifdef MP
uni.getSetting({
success(ress) {
uni.hideLoading();
console.log(ress);
if (!res.authSetting["scope.writePhotosAlbum"]) {
wx.authorize({
scope: "scope.writePhotosAlbum",
success: (ress) => {
console.log(ress);
},
});
} else {
setTimeout(() => {
uni.saveImageToPhotosAlbum({
filePath: imgUrl.value,
success(re) {
uni.hideLoading();
uni.showToast({
title: "保存成功",
icon: "success",
});
},
fail(err) {
console.log(err);
uni.showToast({
title: "保存失败",
icon: "none",
});
},
});
}, 1000);
}
},
});
// #endif
// #ifdef APP-PLUS
setTimeout(() => {
uni.saveImageToPhotosAlbum({
filePath: imgUrl.value,
success(re) {
uni.hideLoading();
uni.showToast({
title: "保存成功",
icon: "success",
});
},
fail(err) {
console.log(err);
uni.showToast({
title: "保存失败",
icon: "none",
});
},
});
}, 1000);
// #endif
},
},
this
);
}, 300);
});
});
};
getSystem();
defineExpose({ drawPoster });
</script>