使用官方组件wxml-to-canvas
的背景
由于现在很多小程序业务都需要生成海报 保存成图片便于用户分享,以往生成canvas的海报需要用户手写canvas对应的JS比较麻烦,所以官方提供了一个组件wxml-to-canvas
,的确方便了不少,但也有一些坑和注意事项。
基础注意事项
- 默认尺寸为400*300,需要在引入的标签里自定义修改。
<wxml-to-canvas class="widget" height="996" width="500"></wxml-to-canvas>
- canvas 支持最大尺寸为 4096,实际像素 < 4096,实际高度需 < 4096/3 = 1356
- 只支持
text
、view
和image
三种标签,text
和image
标签必须指定 width 和 height 属性,否则会导致布局错误。view
可以只制定宽度 - 文字 必须放在
text
中,放在view
中无法显示 - 如果你要设置背景颜色,请使用
backgroundColor
,而非background
,border
同理~ - 多个absolute元素时,因为没有z-index,template元素自上而下渲染,对应z-index依次增高
- 导出图片过大,可以通过
canvasToTempFilePath({fileType, quality})
配置里面的quality
字段来减小
解决一些坑
1、wxml-to-canvas
组件只支持临时地址和网络地址,不支持base64和本地图片,可以通过writeFile
把base64转成临时地址
const fs = wx.getFileSystemManager();
let qrcodeBase64 = QRresult.data;
let qrcodeLink = `${wx.env.USER_DATA_PATH}/qrcodeLink.gif`;
fs.writeFile({
filePath: qrcodeLink,
data: qrcodeBase64,
encoding: 'base64',
success: res => {
console.log(res)
shopJson.qrcode = qrcodeLink;
this.renderToCanvas();
},
fail(res) {
console.error(res)
}
})
2、text
设置不同style不是连续inline-block效果,而是block的换行效果
这个只能通过计算字数来设置text
的width,将不同css的文字连续在一起。
上代码!
- 样式构建代码(仅供参考)
//DEMO.JS 部分参数外部传入
const style = {
canvas_box: {
width: 330,
height: 420,
borderRadius: 20,
backgroundColor: '#fff',
padding: 20,
},
pop_img: {
width: 290,
height: 146,
borderRadius: 20,
overflow: "hidden",
display: "block"
},
pop_h3: {
lineHeight: 24,
height: 24,
paddingTop: 10,
fontSize: 16,
color: "#333",
width: 290,
},
pop_border_bottom: {
width: 290,
height: 1,
backgroundColor: '#eee',
},
pop_h4: {
lineHeight: 20,
paddingTop:10,
width:300,
fontSize: 14,
color: "#666",
paddingBottom: 10,
},
pop_h4_text: {
width: 300,
height: 20,
},
pop_h5: {
lineHeight: 20,
paddingTop: 12,
fontSize: 12,
width: 290,
position: "relative",
zIndex: 2,
},
pop_h5_txt: {
fontSize: 12,
color: "#000",
height: 20,
},
pop_orange: {
fontSize: 12,
color: "#FD6805",
height: 20,
},
pop_hint: {
position: "absolute",
right: 20,
bottom: 20,
width: 290,
height: 20,
display: "block",
},
pop_hint_txt: {
height: 20,
width: 290,
fontSize: 12,
color: "#999",
},
pop_QRcode: {
position: "absolute",
right: 20,
bottom: 20,
width: 90,
height: 90,
display: "block",
zIndex: 1,
},
}
const poster = (shop: any) => {
if (shop) {
console.log(shop.address.length)
//判断文字是否过长
if(shop.address && shop.address.length > 20){
shop.allAddress = `<view class="pop_h4"><text class="pop_h4_text">${shop.address.slice(0, 20)}</text><text class="pop_h4_text">${shop.address.slice(20)}</text></view>`
}else {
shop.allAddress = `<view class="pop_h4"><text class="pop_h4_text">${shop.address}</text></view>`
}
const wxml = `
<view class="canvas_box">
<image class="pop_img" mode="widthFix" src="${shop.img}" />
<view class="pop_h3"><text class="pop_h3">这里是名字</text></view>
${shop.allAddress}
<view class="pop_border_bottom"></view>
<view class="pop_h3"><text class="pop_h3">这里是title</text></view>
<image class="pop_QRcode" src="${shop.qrcode}" />
<view class="pop_h5"><text class="pop_h5_txt">最新活动请扫码</text><text class="pop_orange">扫描二维码享受店家专属折扣!</text></view>
<view class="pop_hint"><text class="pop_hint_txt">神秘社区强力支持</text></view>
</view>`
return {
wxml,
style
};
}
}
module.exports = {
poster,
}
let shopJson = {
name: "皮卡球",
address: "阿罗拉阿罗拉",
img: "https://aaa.png",
qrcode: "https://aaa.png",
};
page({
renderToCanvas() {
let { wxml, style } = poster(shopJson);
const p1 = this.widget.renderToCanvas({ wxml, style })
console.log(p1)
p1.then((res: any) => {
console.log('container', res.layoutBox)
this.container = res
})
},
})
- 将转化好的canvas保存到手机中
const p2 = this.widget.canvasToTempFilePath();
p2.then((res: any) => {
console.log(res.tempFilePath);
//保存到本地
wx.saveImageToPhotosAlbum({
filePath: res.tempFilePath,
success(res) {
console.log(res);
wx.showToast({
title: "保存成功",
icon: "success",
duration: 2000,
});
},
//被拒绝后的操作
fail(res) {
console.log(res);
wx.showModal({
title: "提示",
content: "保存失败,重新打开",
success(res) {
if (res.confirm) {
console.log("用户点击确定");
wx.getSetting({
success(res) {
console.log(res.authSetting);
},
});
}
},
});
},
});
});
官方地址
代码片段