一、需求

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

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

二、官方示例使用方法

        1.安装wxml-to-canvas

npm install --save wxml-to-canvas

        2.JSON 组件声明

{
  "usingComponents": {
    "wxml-to-canvas": "wxml-to-canvas",
  }
}

         3.wxml 引入组件

<video class="video" src="{{src}}">
  <wxml-to-canvas class="widget"></wxml-to-canvas>
</video>
<image src="{{src}}" style="width: {{width}}px; height: {{height}}px"></image>

        4. js 获取实例

const {wxml, style} = require('./demo.js')
Page({
  data: {
    src: ''
  },
  onLoad() {
    this.widget = this.selectComponent('.widget')
  },
  renderToCanvas() {
    const p1 = this.widget.renderToCanvas({ wxml, style })
    p1.then((res) => {
      this.container = res
      this.extraImage()
    })
  },
  extraImage() {
    const p2 = this.widget.canvasToTempFilePath()
    p2.then(res => {
      this.setData({
        src: res.tempFilePath,
        width: this.container.layoutBox.width,
        height: this.container.layoutBox.height
      })
    })
  }
})

三、实际项目

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

        1.wxml

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

        2.js文件

const net = require('../../../common/network.js');
//⚠️海报内容和样式
const { wxml, style } = require('./canvas.js');
//自己封装的微信api
import wxApi from '../../../common/wxApi';
const app = getApp();
Page({
    /**
     * 页面的初始数据
     */
    data: {
    },
    /**
     * 生命周期函数--监听页面加载
     */
    onLoad(options) {
        wx.showLoading({
            title: '海报生成中...',
        });
        //获取页面初始数据
        this.getServerData();
    },
    getServerData() {
        net.posterInfo().then((response) => {
            const { name, title, teacher, qr_code, task_id } = response.data;
            const { real_name, avatarurl, nickname } = app.globalData.userInfo;
            //画海报用到的数据
            this.setData({
                info: response.data,
                avatarurl,
                name,
                title,
                teacher,
                qr_code,
            });
            //注意⚠️:这里是对页面初始渲染
            this.widget = this.selectComponent('.widget');
            const _wxml = wxml(name, avatarurl, title, teacher, qr_code);
            //onload方法里节点没加载完,设置定时器
            setTimeout(() => {
                //渲染到 canvas,传入 wxml 模板 和 style 对象,返回的容器对象包含布局和样式                            
                //信息。
                const p1 = this.widget.renderToCanvas({
                    wxml: _wxml,
                    style,
                });
                p1.then((res) => {
                    this.container = res;
                    wx.hideLoading();
                });
            }, 500);
        });
    },
    preservation() {
        // this.widget = this.selectComponent('.widget')
        const { task_id } = this.data;
        const p2 = this.widget.canvasToTempFilePath();
        p2.then((res) => {
            //保存到本地相册
            wxApi.apiScopeOauth('scope.writePhotosAlbum').then(() => {
                wx.saveImageToPhotosAlbum({
                    filePath: res.tempFilePath,
                    success(res) {
                        util.showToast(
                            '海报已保存,快去朋友圈分享吧!',
                            'none',
                            3000
                        );
                    },
                    fail(res) {
                        wx.showToast({
                            icon: 'error',
                            title: '保存图片失败!',
                        });
                    },
                });
            });
        }).catch((fail) => {
            wx.showToast({
                icon: 'error',
                title: '请稍后再试',
            });
        });
    },
});

        3.canvas.js

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

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

const wxml = ( name, avatarurl,title,teacher,qr_code ) => {
    return `
    <view class="poster-wapper">
        <image class="poster-img" src=""/>
        <view class="author">
            <text class="author-text">作者:${name}</text>
        </view>
        <view class="head">
            <view class="head-border">
                <image class="head-img" src="${avatarurl}"></image>
            </view>
        </view>
        <view class="poster-info">
            <view class="info">
                <text class="title">挑战内容:《${title}》</text>
                `+ (teacher?`<text class="teacher">老师:${teacher}</text>`:'')
                +` <view class="line"></view>
                    <text class="tip">本次朗读近乎完美!快来听听吧!</text>
            </view>
            <image class="qrcode-img" src="${qr_code}" />
        </view>
    </view>
    `
}
const style = {
    posterWapper:{
        display: 'flex',
        flexDirection: 'column',
        alignItems: 'center',
        justifyContent: 'center',
        position: 'relative',
    },
    posterImg: {
        width: 325,
        height: 550
    },
    author: {
        width: 119,
        height: 32,
        borderRadius: 12,
        backgroundColor: 'rgba(255,255,255,0.8)',
        position: 'absolute',
        paddingLeft: 18,
        top: 353,
        left: 45,
    },
    authorText: {
        width: 98,
        height: 32,
        paddingLeft: 13.5,
        fontSize: 11,
        fontWeight: 600,
        color: '#333333',
        verticalAlign: 'middle',
    },
    head: {
        width: 51,
        height: 51,
        borderRadius: 25.5,
        display: 'flex',
        alignItems: 'center',
        justifyContent: 'center',
        position: 'absolute',
        top: 343,
        left: 12,
        backgroundColor: 'rgba(255,255,255,0.8)',
    },
    headBorder: {
        width: 46,
        height: 46,
        backgroundColor: 'rgba(255,255,255)',
        borderRadius: 23,
        display: 'flex',
        alignItems: 'center',
        justifyContent: 'center',
    },
    headImg: {
        width: 43,
        height: 43,
        borderRadius: 20,
    },
    posterInfo:{
        position: 'absolute',
        bottom: -6,
        width: 325,
        height: 143,
        backgroundColor: '#FFFFFF',
        borderRadius: 10,
        display: 'flex',
        flexDirection: 'row'
    },
    info: {
        width: 210,
        height: 140,
        display: 'flex',
        flexDirection: 'column',
        justifyContent: 'center',
        paddingTop: 6,
        paddingLeft: 15
    },
    title: {
        width: 210,
        height: 24,
        fontSize: 13,
        fontWeight: 600,
        color: '#333333',
        lineHeight: 24
    },
    teacher:{
        width: 210,
        height: 24,
        fontSize: 13,
        fontWeight: 400,
        color: '#666666',
        lineHeight: 24,
    },
    line:{
        width: 190,
        height: 1,
        backgroundColor: 'rgba(3,0,0,0.16)'
    },
    tip: {
        height: 24,
        width: 210,
        fontSize: 13,
        fontFamily: 'PingFang SC',
        fontWeight: 600,
        color: '#333333',
        lineHeight: 24,
    },
    btn:{
        width: 140,
        height: 33,
        backgroundColor: '#FF6000',
        borderRadius: 19,
        lineHeight: 33,
        textAlign: 'center',
        marginTop: 7.5,
        position: 'relative'
    },
    btnText:{
        width: 140,
        height: 33,
        fontSize: 18,
        fontFamily: 'PingFang SC',
        fontWeight: 600,
        color: '#FFFFFF',
    },
    btnImg:{
        width:37,
        height:18,
        position: 'absolute',
        left: 150,
        top: 9
    },
    qrcodeImg:{
        width: 92,
        height: 92,
        marginLeft: 5,
        position: 'absolute',
        bottom: 33,
        right: 12
    }
}
module.exports = {
    wxml,
    style
}
  

注意点⚠️:

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

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

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

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

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

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

补充:(2022/12/15)

背景图片在开发工具和开发版都可以正常显示,但是在体验版显示不出来;

图片的域名在项目配置里没有,在后台管理-开发设置-服务器域名-request合法域名-配置图片的域名即可正常显示。

发表回复