• 微信小程序插件--wxml-to-canvas(生成图片)


    一、需求

            项目中要实现一个将图片分享到朋友圈的功能,将生成的海报转成图片保存到手机。用到了wxml-to-canvas插件。

    二、官方示例使用方法

            1.安装wxml-to-canvas

    npm install --save wxml-to-canvas
    

            2.JSON 组件声明

    1. {
    2. "usingComponents": {
    3. "wxml-to-canvas": "wxml-to-canvas",
    4. }
    5. }

             3.wxml 引入组件

    1. <video class="video" src="{{src}}">
    2. <wxml-to-canvas class="widget">wxml-to-canvas>
    3. video>
    4. <image src="{{src}}" style="width: {{width}}px; height: {{height}}px">image>

            4. js 获取实例

    1. const {wxml, style} = require('./demo.js')
    2. Page({
    3. data: {
    4. src: ''
    5. },
    6. onLoad() {
    7. this.widget = this.selectComponent('.widget')
    8. },
    9. renderToCanvas() {
    10. const p1 = this.widget.renderToCanvas({ wxml, style })
    11. p1.then((res) => {
    12. this.container = res
    13. this.extraImage()
    14. })
    15. },
    16. extraImage() {
    17. const p2 = this.widget.canvasToTempFilePath()
    18. p2.then(res => {
    19. this.setData({
    20. src: res.tempFilePath,
    21. width: this.container.layoutBox.width,
    22. height: this.container.layoutBox.height
    23. })
    24. })
    25. }
    26. })

    三、实际项目

            安装、json配置、wxml引入都一样。

            1.wxml

    1. <wxml-to-canvas class="widget" width="325" height="550">wxml-to-canvas>
    2. <view class='save flex-center-center' bindtap='preservation'>
    3. 保存海报
    4. view>

            2.js文件

    1. const net = require('../../../common/network.js');
    2. //⚠️海报内容和样式
    3. const { wxml, style } = require('./canvas.js');
    4. //自己封装的微信api
    5. import wxApi from '../../../common/wxApi';
    6. const app = getApp();
    7. Page({
    8. /**
    9. * 页面的初始数据
    10. */
    11. data: {
    12. },
    13. /**
    14. * 生命周期函数--监听页面加载
    15. */
    16. onLoad(options) {
    17. wx.showLoading({
    18. title: '海报生成中...',
    19. });
    20. //获取页面初始数据
    21. this.getServerData();
    22. },
    23. getServerData() {
    24. net.posterInfo().then((response) => {
    25. const { name, title, teacher, qr_code, task_id } = response.data;
    26. const { real_name, avatarurl, nickname } = app.globalData.userInfo;
    27. //画海报用到的数据
    28. this.setData({
    29. info: response.data,
    30. avatarurl,
    31. name,
    32. title,
    33. teacher,
    34. qr_code,
    35. });
    36. //注意⚠️:这里是对页面初始渲染
    37. this.widget = this.selectComponent('.widget');
    38. const _wxml = wxml(name, avatarurl, title, teacher, qr_code);
    39. //onload方法里节点没加载完,设置定时器
    40. setTimeout(() => {
    41. //渲染到 canvas,传入 wxml 模板 和 style 对象,返回的容器对象包含布局和样式
    42. //信息。
    43. const p1 = this.widget.renderToCanvas({
    44. wxml: _wxml,
    45. style,
    46. });
    47. p1.then((res) => {
    48. this.container = res;
    49. wx.hideLoading();
    50. });
    51. }, 500);
    52. });
    53. },
    54. preservation() {
    55. // this.widget = this.selectComponent('.widget')
    56. const { task_id } = this.data;
    57. const p2 = this.widget.canvasToTempFilePath();
    58. p2.then((res) => {
    59. //保存到本地相册
    60. wxApi.apiScopeOauth('scope.writePhotosAlbum').then(() => {
    61. wx.saveImageToPhotosAlbum({
    62. filePath: res.tempFilePath,
    63. success(res) {
    64. util.showToast(
    65. '海报已保存,快去朋友圈分享吧!',
    66. 'none',
    67. 3000
    68. );
    69. },
    70. fail(res) {
    71. wx.showToast({
    72. icon: 'error',
    73. title: '保存图片失败!',
    74. });
    75. },
    76. });
    77. });
    78. }).catch((fail) => {
    79. wx.showToast({
    80. icon: 'error',
    81. title: '请稍后再试',
    82. });
    83. });
    84. },
    85. });

            3.canvas.js

                    只展示大体框架,具体内容涉及隐私去掉了。

                    wxml返回的是页面内容的字符串。

    1. const wxml = ( name, avatarurl,title,teacher,qr_code ) => {
    2. return `
    3. 作者:${name}
    4. ${avatarurl}">
    5. 挑战内容:《${title}
    6. `+ (teacher?`老师:${teacher}`:'')
    7. +`
    8. 本次朗读近乎完美!快来听听吧!
    9. ${qr_code}" />
    10. `
    11. }
    12. const style = {
    13. posterWapper:{
    14. display: 'flex',
    15. flexDirection: 'column',
    16. alignItems: 'center',
    17. justifyContent: 'center',
    18. position: 'relative',
    19. },
    20. posterImg: {
    21. width: 325,
    22. height: 550
    23. },
    24. author: {
    25. width: 119,
    26. height: 32,
    27. borderRadius: 12,
    28. backgroundColor: 'rgba(255,255,255,0.8)',
    29. position: 'absolute',
    30. paddingLeft: 18,
    31. top: 353,
    32. left: 45,
    33. },
    34. authorText: {
    35. width: 98,
    36. height: 32,
    37. paddingLeft: 13.5,
    38. fontSize: 11,
    39. fontWeight: 600,
    40. color: '#333333',
    41. verticalAlign: 'middle',
    42. },
    43. head: {
    44. width: 51,
    45. height: 51,
    46. borderRadius: 25.5,
    47. display: 'flex',
    48. alignItems: 'center',
    49. justifyContent: 'center',
    50. position: 'absolute',
    51. top: 343,
    52. left: 12,
    53. backgroundColor: 'rgba(255,255,255,0.8)',
    54. },
    55. headBorder: {
    56. width: 46,
    57. height: 46,
    58. backgroundColor: 'rgba(255,255,255)',
    59. borderRadius: 23,
    60. display: 'flex',
    61. alignItems: 'center',
    62. justifyContent: 'center',
    63. },
    64. headImg: {
    65. width: 43,
    66. height: 43,
    67. borderRadius: 20,
    68. },
    69. posterInfo:{
    70. position: 'absolute',
    71. bottom: -6,
    72. width: 325,
    73. height: 143,
    74. backgroundColor: '#FFFFFF',
    75. borderRadius: 10,
    76. display: 'flex',
    77. flexDirection: 'row'
    78. },
    79. info: {
    80. width: 210,
    81. height: 140,
    82. display: 'flex',
    83. flexDirection: 'column',
    84. justifyContent: 'center',
    85. paddingTop: 6,
    86. paddingLeft: 15
    87. },
    88. title: {
    89. width: 210,
    90. height: 24,
    91. fontSize: 13,
    92. fontWeight: 600,
    93. color: '#333333',
    94. lineHeight: 24
    95. },
    96. teacher:{
    97. width: 210,
    98. height: 24,
    99. fontSize: 13,
    100. fontWeight: 400,
    101. color: '#666666',
    102. lineHeight: 24,
    103. },
    104. line:{
    105. width: 190,
    106. height: 1,
    107. backgroundColor: 'rgba(3,0,0,0.16)'
    108. },
    109. tip: {
    110. height: 24,
    111. width: 210,
    112. fontSize: 13,
    113. fontFamily: 'PingFang SC',
    114. fontWeight: 600,
    115. color: '#333333',
    116. lineHeight: 24,
    117. },
    118. btn:{
    119. width: 140,
    120. height: 33,
    121. backgroundColor: '#FF6000',
    122. borderRadius: 19,
    123. lineHeight: 33,
    124. textAlign: 'center',
    125. marginTop: 7.5,
    126. position: 'relative'
    127. },
    128. btnText:{
    129. width: 140,
    130. height: 33,
    131. fontSize: 18,
    132. fontFamily: 'PingFang SC',
    133. fontWeight: 600,
    134. color: '#FFFFFF',
    135. },
    136. btnImg:{
    137. width:37,
    138. height:18,
    139. position: 'absolute',
    140. left: 150,
    141. top: 9
    142. },
    143. qrcodeImg:{
    144. width: 92,
    145. height: 92,
    146. marginLeft: 5,
    147. position: 'absolute',
    148. bottom: 33,
    149. right: 12
    150. }
    151. }
    152. module.exports = {
    153. wxml,
    154. style
    155. }

    注意点⚠️:

            1.wxml支持 viewtextimage 三种标签,通过 class 匹配 style 对象中的样式。

            2.css对象属性值为对应 wxml 标签的 class 驼峰形式。需为每个元素指定 width 和 height 属性,否则会导致布局错误。

            3.存在多个 className 时,位置靠后的优先级更高,子元素会继承父级元素的可继承属性。

    元素均为 flex 布局。left/top 等 仅在 absolute 定位下生效。

            4.css不支持背景图片,在wxml中用img代替。

            5.在写text标签时外边必须套一层view标签,否则不显示。(这一点是我遇到的问题,不知道是不是这样规定)

  • 相关阅读:
    [leetcode hot 150]第十五题,三数之和
    Discourse 如何在 header 上添加 HTML
    Mac下搭建Texstudio+Textlive(Mactex)
    【2023年11月第四版教材】第13章《资源管理》(第一部分)
    《白帽子讲web安全》笔记
    【项目】云备份系统基础功能实现
    linux安装jdk rpm:如何在Linux上使用RPM安装JDK
    956. 最高的广告牌
    解释Java中的反射API
    【考研数学】概率论如何复习?跟谁好?
  • 原文地址:https://blog.csdn.net/animatecat/article/details/125981963