微信小程序生成海报

各个文件源码

为了优化生成海报的时候较慢,可以刚进入页面的时候就生成海报,但是设置opacity:0;z-index:-1;,等用户点击查看我的海报时,再设置opacity:1;z-index:99;

wxml、styles可根据后端返回的字段动态生成

  • 文字必须text标签包裹
  • 样式的height必须是fontSize的2.6倍取整(大概这个范围)元素才会显示
  • 元素的width可以根据动态设置
  • 必须给每一个元素都设置宽和高,并且是数值不带任何单位
  • 调用this.widget.renderToCanvas 方法的时候 属性名必须是wxml和 style
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
const wxml = (msg) => { 
return `
<view class="container" >
<image class="img" src="${msg.img}"></image>
<view class="day-txt">
<text class="day-tips">您已累计出行</text>
<text class="day">${msg.day}</text>
<text class="day-tips">天</text>
</view>
<view class="yuan-txt">
<text class="yuan-tips">XXXXX已帮您捐出</text>
<text class="yuan">${msg.yuan}</text>
<text class="yuan-tips">元</text>
</view>
</view>
`
}

const style = (styles) => {
return {
container: {
width: 340,
height: 507,
flexDirection: 'column',
backgroundColor: 'transparent',
},
dayTxt: {
position: 'absolute',
left: 50,
top: 319,
fontWeight: 500,
width: 300,
height: 34,
flexDirection: 'row',
},
dayTips: {
width: 78,
fontSize: 13,
height: 34,
color: '#333333',
textAlign: 'left'
},
day: {
width: styles.dayWidth,
verticalAlign: 'top',
fontSize: 15, // 此属性要生效,height必须足够高
height: 40,
color: '#FF1E37',
textAlign: 'center',
},
yuanTxt: {
position: 'absolute',
left: 50,
top: 341,
fontWeight: 500,
width: 300,
height: 38,
flexDirection: 'row',
},
yuanTips: {
width: 160,
fontSize: 20,
height: 52,
color: '#333333',
textAlign: 'left'
},
yuan: {
fontWeight: 'bold',
width: 60,
fontSize: 26, // 设计稿的一半
height: 68, // fantasize * 2.6倍 取整
lineHeight: 26,
color: '#FF1E37',
textAlign: 'center',
verticalAlign: 'top',
},
img: {
width: 340,
height: 507,
borderRadius: 20,
}
}
}

module.exports = {
wxml,
style
}

index.wxml文件

  • show-menu-by-longpress="true" 长按触发保存图片、收藏、转发
  • wxml-to-canvas内容绘制成canvas
  • imagecanvas转化成图片
  • 想要canvas不被用户看见,外层包一个<view class="poster-canvas">,设置position定位
    1
    2
    3
    4
    .poster-canvas {
    position: fixed;
    left: -10000rpx;
    }
1
2
3
4
5
6
7
8
9
10
11
12
13
<view class="poster-back" style="{{posterStyle}}">
<view class="poster-canvas">
<wxml-to-canvas
class="widget"
width="{{width}}"
height="{{height}}"></wxml-to-canvas>
</view>
<image
src="{{src}}"
class="poster-img"
show-menu-by-longpress="true"></image>
<view class="close-icon" bindtap="close"></view>
</view>

index.json文件

  • 如果想不占用主包体积,可以将npm构建后生成的组件移动到该分包下,直接移动miniprogram_npm文件,json中引用的路径不用变更
1
2
3
4
5
6
{
"component": true,
"usingComponents": {
"wxml-to-canvas": "wxml-to-canvas"
}
}

index.js文件

  • wx.getSystemInfo拿到pixelRatio,结合设备分辨率,提高图片清晰度
  • 延迟(setTimeout)生成canvas,防止有些机型或网络下,canvasToTempFilePath失败
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
const { wxml, style } = require('./poster.js')
import { getSystemInfo } from '@utils/common';
Component({
properties: {
posterStyle: {
type: String,
value: 'opacity:0;z-index:-1;'
},
info: {
type: Object,
value: {
day: 50,
yuan: 0.5,
img: 'XXXXX.png'
}
},
},
/**
* 组件的初始数据
*/
data: {
src: '',
width: 340,
height: 507,
},
methods: {
renderToCanvas() {
console.log('wxml', wxml)
let wxmlData = wxml(this.data.info)
let styleData = style({
dayWidth: (this.data.info.day?.length * 12) || 24,
yuanWidth: (this.data.info.yuan?.length * 12) || 60
})
console.log('wxmlData', wxmlData)
const p1 = this.widget.renderToCanvas({ wxml:wxmlData, style:styleData })
console.log('p1', p1)
p1.then((res) => {
console.log('container', res.layoutBox)
this.container = res
this.extraImage()
}, rej => {
console.log('renderError', rej)
})
},
extraImage() {
const sysInfo = getSystemInfo();
const pixRatio = sysInfo?.pixelRatio || 1 // 结合设备分辨率,提高图片清晰度
console.log(1111, sysInfo, pixRatio)
const p2 = this.widget.canvasToTempFilePath()
console.log(22222, p2)
p2.then(res => {
console.log('成功了吗', res)
this.setData({
src: res.tempFilePath,
width: this.container.layoutBox.width * pixRatio,
height: this.container.layoutBox.height * pixRatio
})
},rej =>{
console.log('错误', rej)
})
},
close() {
this.triggerEvent('close')
}
},
ready() {
this.widget = this.selectComponent('.widget')
setTimeout(() => {
this.renderToCanvas()
}, 1000);
}
})

js文件 根据不同机型大小改变海报宽高 动态缩小 最大宽度

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
ready() {
const sysInfo = getSystemInfo();
console.log('系统信息', sysInfo)
let sysWid = Number(sysInfo?.screenWidth)
let sysHei = Number(sysInfo?.screenHeight)
let screenWidth = ( sysWid|| 306) * 1.632
if (sysWid >= 375) { // 最大宽度
screenWidth = 375 * 1.632
}
if (sysHei <= 700) { // 高度过高,则宽度缩小
screenWidth = screenWidth/1.2
}
console.log('宽度', screenWidth)
const screenHeight = screenWidth * 1.81
const borderRadius = screenWidth/61.2
const imgTop = screenWidth/3.29
const saveTxtTop = imgTop + screenHeight + screenWidth/15.3
const closeIconTop = saveTxtTop + screenWidth/6.8
const txtLeft = screenWidth/13
const dayTxtTop = screenWidth/1.57
const yuanTxtTop = screenWidth/1.5

this.setData({
imgWidth: screenWidth,
imgHeight: screenHeight,
saveTxtTop,
closeIconTop,
imgTop,
txtLeft,
borderRadius,
dayTxtTop,
yuanTxtTop
})
console.log(1111, sysInfo)
}

Powered by Hexo and Hexo-theme-hiker

Copyright © 2013 - 2024 HL's Blog All Rights Reserved.

UV : | PV :