uniapp小程序使用wxml-to-canvas生成图片

开发框架:uniapp

场景:小程序保存页面为图片并上传

尝试方案:使用html-to-canvas,问题:小程序不允许操作dom,也无法获取dom标签,只能通过wx.createSelectorQuery()获取dom信息。

微信小程序官方解决方案:wxml-to-canvas。问题:只支持wxml的原生小程序canvas图片生成,相关配置也是原生小程序的配置。

解决方案:

1、打开微信小程序官方代码片段代码片段

2、在程序根目录下新建wxcomponents文件夹,将代码片段中的miniprogram_npm下的widget-ui和wxml-to-canvas两个文件夹复制进去

3、将/wxcomponents/wxml-to-canvas/index.js中的

module.exports = require("widget-ui");
//改为
module.exports = require("../widget-ui/index.js")

4、配置pages.json(这样uni-app才会打包wxcomponents)

"pages": [
    {
        "path": "pages/share",
        "style": {
            "usingComponents": {
              "wxml-to-canvas": "/wxcomponents/wxml-to-canvas/index"
            }
        }
    },
...
]

5、主页面 pages/share.vue

<template>
    <view class="share-page">
        <view class="share-page-box" id="box" v-if="show"
            :style="{width: canvasWidth + 'px', height: canvasHeight + 'px' }">
            <wxml-to-canvas class="widget" :width="canvasWidth" :height="canvasHeight"></wxml-to-canvas>
        </view>
        <view class="share-page-btn" @tap="extraImage">
            <button class="btn-big" :style="getBtnStyle">保存图片</button>
        </view>
    </view>
</template>
<script>
    const {
        wxml,
        style
    } = require('./domData.js')
    export default {
        name: '',
        data() {
            return {
                show: false, // 是否显示canvas
                canvasWidth: 320, // 默认canvas宽高
                canvasHeight: 480,
                screenWidth: null, // 设备宽度
                screenHeight: null, // 设备宽度
                name: '',
                pic: '',
                chapter: '',
                widget: null,
            }
        },
        onLoad(options) {
            console.log('options', options);
            this.name = 'wxml生成canvas(liangtao)'
            this.pic = 'https://pic1.zhimg.com/80/v2-58fe538a59f870407b1435bfd45893ed_720w.jpeg'
            this.chapter = ['第一段对话','第二段对话','第三段对话','第四段对话','第五段对话','第六段对话','第七段对话','第八段对话','第九段对话','第十段对话','第十一段对话','第十二段对话','第十三段对话']
            // 获取设备信息
            wx.getSystemInfo({
                success: (res) => {
                    console.log("设备信息",res);
                    this.screenWidth = res.screenWidth
                    this.screenHeight = 1000//高度建议计算得出或写死。如使用res.screenHeight,文字过长时无法生成
                    this.canvasWidth = this.screenWidth 
                    this.canvasHeight = this.screenHeight
                    this.show = true
                    // 数字容器宽度 动态设置 
                    setTimeout(() => {
                        wx.showLoading({
                            title: '图片生成中...'
                        })
                        this.widget = this.selectComponent('.widget')
                        this.renderToCanvas()
                    }, 1000)
                }
            });
        },
        methods: {
            // wxml 转 canvas
            renderToCanvas() {
                console.log('this.widget', this.widget)
                const _wxml = wxml(this.name, this.pic, this.chapter)//调用wxml
                const _style = style(this.screenWidth, this.canvasWidth, this.canvasHeight)
                const p1 = this.widget.renderToCanvas({
                    wxml: _wxml,
                    style: _style
                })
                p1.then((res) => {
                    console.log('生成成功');
                    wx.hideLoading()
                }).catch((err) => {
                    console.log('生成失败')
                })
            },
            // 保存图片
            extraImage() {
                const p2 = this.widget.canvasToTempFilePath()
                let that = this
                p2.then(result => {
                    let path = result.tempFilePath
                    console.log(path);
                })
            },
        }
    }
</script>

 

6、配置wxml页面 /pages/domData.js

const wxml = (name, pic, c1) => `
<view class="container">
    <image src="` + pic + `"  class="pic"/>
    <text class="name">${name}</text>
    <text class="content">` + c1[0] + `</text>
    <text class="content">` + c1[1] + `</text>
    <text class="content">` + c1[2] + `</text>
    <text class="content">` + c1[3] + `</text>
    <text class="content">` + c1[4] + `</text>
    <text class="content">` + c1[5] + `</text>
    <text class="content">` + c1[6] + `</text>
    <text class="content">` + c1[7] + `</text>
    <text class="content">` + c1[8] + `</text>
    <text class="content">` + c1[9] + `</text>
    <text class="content">` + c1[10] + `</text>
    <text class="content">` + c1[11] + `</text>
    <text class="content">` + c1[12] + `</text>
</view>
`

/**
 * @param {*} screenWidth 屏幕宽度
 * @param {*} canvasWidth  画布宽度
 * @param {*} canvasHeight  画布高度
 * @param {*} numberWidth  数字宽度,动态设置
 * @return {*} 
 */
const style = (screenWidth, canvasWidth, canvasHeight) => {
    return {
        "container": {
            width: canvasWidth,
            height: canvasHeight,
            position: 'relative',
            overflow: 'hidden',
            backgroundColor: '#ffffff',
        },
        "name": {
            fontSize: 20,
            color: '#333',
            marginLeft: canvasWidth * 0.08,
            width: canvasWidth * 0.84,
            height: screenWidth * 0.18,
            textAlign: 'center',
        },
        "content": {
            fontSize: 14,
            color: '#333',
            width: canvasWidth * 0.84,
            height: screenWidth * 0.15,
            marginLeft: canvasWidth * 0.08,
        },
        "pic": {
            width: canvasWidth * 0.3,
            height: screenWidth * 0.28,
            marginTop: canvasWidth * 0.1,
            marginLeft: canvasWidth * 0.35,
            marginBottom: canvasWidth * 0.05,
            borderRadius: screenWidth * 0.14,
            overflow: 'hidden',
        },
    }
}

module.exports = {
    wxml,
    style
}

需要说明一点,此处的wxml返回的是字符串,也就是页面实际呈现的结果,不可以在里面写wx:if,wx:for等语法。

如果需要加,在箭头函数里面直接用js写法,去判断和遍历,然后return字符串。

 7、最终效果

 

wxml-to-canvas要注意的一些问题

1、只能画view,text,img
2、每个元素必须要设置宽高
3、默认是flex布局,可以通过flexDirection: "column"来改变排列方式

 

posted @ 2022-09-22 15:47  梁涛999  阅读(6577)  评论(0编辑  收藏  举报