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"来改变排列方式