如果需要实现将小程序的页面转为图片,第一步是要先把页面转为canvas,再将canvas转为图片。本人使用的是Wxml2Canvas这个插件。其实最开始使用的是wxml-to-canvas这个官方自带的组件。由于这个组件坑太多,本地调试一切正常,但是到了真机调试就会出现创建画布失败的情况,寻找了很久,最多的方法方法就是添加延时器,或者画布的高度设置在1000px以内。但是都没有什么鬼用,最终无可奈何,只能换个插件,重新写。好惨一男的😥

那我们废话不多说,准备开始搞事情!!

第一步 安装插件

注意 安装之后别忘了构建npm

 npm install wxml2canvas

第二步 引入

import Wxml2Canvas from 'wxml2canvas'; 

第三步 使用

首先需要在页面上创建一个canvas以及需要生成图片的结构

<canvas canvas-id="share"></canvas>

<view class="share__canvas share__canvas1">
    <view class="share__canvas1-text draw_canvas" 
        data-type="text" data-text="这是一段无边距文字">
        这是一段无边距文字
    </view>
</view>

 如果需要使用到图片,其中data-url是图片在canvas显示的地址,即:

<image class="draw_canvas" 	data-type="image" 
    data-url="/static/share/friend_logo.png" 
    data-delay="1" mode="aspectFit" src="/static/share/friend_logo.png"></image>

其中,还有text标签可以使用,必填属性为data-type,声明此标签的在canvas中展示类型,每个标签都有data-top和data-left的属性,分别代表元素参照与自身位置的偏移值。 需要注意的是,data-text是生成的canvas中显示的文字,可以理解为标签的自定义属性,也可以接受变量等。


写入事件,用于获取id为wxml-canvas的宽高,这里的获取的元素的宽高就是将来生成canvas的父元素,获取之后触发draw函数。

//动态获取画制作元素的宽高
drawCanvas: function () {
    const query = wx.createSelectorQuery().in(this);
    query.select('#wxml-canvas').fields({
        size: true,
        scrollOffset: true
    }, data => {
        let width = data.width;
        let height = data.height;
        this.width = width;
        this.height = height;
        setTimeout(() => {
            this.draw()
        }, 1500);
}).exec();

draw函数: 

  draw() {
    let that = this

    //创建wxml2canvas对象
    let drawImage = new Wxml2Canvas({
      element: 'share', // canvas节点的id,
      obj: that, // 在组件中使用时,需要传入当前组件的this
      width: this.width * 2, // 宽高
      height: this.height * 4,
      background: '#fff', // 默认背景色
      progress(percent) { // 绘制进度
      },
      finish(url) {
        console.log("创建的图片", url);
      },
      error(res) {
        console.log(res);
        // uni.hideLoading()
        // 画失败的原因
      }
    }, this);
    let data = {
      //直接获取wxml数据
      list: [{
          type: 'wxml',
          class: '.long_friend  .draw_canvas',
          limit: '.long_friend ',
          x: 0,
          y: 0
        } ]
    }
  //传入数据,画制canvas图片
  drawImage.draw(data, this);
},

解读draw函数

创建wxml2canvas对象

这一步是为了创建wxml2canvas对象,其中传入的参数有三个,第一个参数为一个对象option。第二个参数为创建图片成功时的回调函数,成功时的回调函数第一个参数为图片的地址。第三个参数为失败时的回调函数,会返回失败原因以及状态码,第四个参数传this,是为了防止“canvasToTempFilePath: fail canvas is empty ”报错,报这个错是因为调取wx.canvasToTempFilePath 接口获取不到canvas,同样的需要传入上下文的this。

其中option的宽高,也是生成图片的宽高,我将其设置为元素的初始宽度的两倍,是因为如果是等比的话,图片会模糊。如果发现将宽高*2还是出现图片糊的情况,可以适当调整倍数。

 //创建wxml2canvas对象
    let drawImage = new Wxml2Canvas({
      element: 'share', // canvas节点的id,
      obj: that, // 在组件中使用时,需要传入当前组件的this
      width: this.width * 2, // 宽高
      height: this.height * 2,
      background: '#fff', // 默认背景色
      progress(percent) { // 绘制进度
      },
      finish(url) {
        console.log("创建的图片", url);
      },
      error(res) {
        console.log(res);
        // uni.hideLoading()
        // 画失败的原因
      }
    }, this);

初始化属性option,其属性属性如下:

属性名 类型 默认值 是否必填 说明
element String “” 画布的id
width Number 0 画布的宽,以iphone6的375为基准,其他机型按比例自动设置实际宽度
height Number 0 画布的高,同上
destZoom Number 3 输出的图片的像素密度,不建议传值,如果需要控制图片大小,可以适当减小
zoom Number 1 画布整体缩放比例,不建议传值,会覆盖各种机型的适配
translateX Number 0 画布整体横向位移
translateY Number 0 画布整体纵向位移
height Number height * 2 输出的图片的高度
background String #ffffff 画布的整体背景色
gradientBackground Object null 画布整体的渐变背景色
finish Function null 绘制成功后回调函数, 返回值url,绘制图片的本地路径
progress Function null 绘制进度,返回值percent,0-100
error Function null 绘制失败后回调函数,返回值object,包含具体原因

 绘制失败的原因如下:

错误码 原因 说明
errcode errmsg e
1000 save canvas error 保存图片失败
1001 download pic error 预下载图片失败
1002 drawRect error 绘制矩形失败
1003 drawImage error 绘制图片失败
1004 drawText error 绘制文本失败
1005 drawCircle error 绘制圆形图片失败
1006 drawCircleImage error 绘制圆形失败
1007 drawLine error 绘制线条失败
1008 drawWxml error 绘制Wxml失败
1009 drawWxml preLoadImage error 预下载Wxml图片失败

表格数据转载自:https://github.com/liudongyun1215/wxml2canvas

函数内声明的data对象:

这里的type可以为矩形(rect),圆形(circle),线条(line),图片(image),文本(text)等,声明type为wxml时,会查询绘制元素节点的样式并绘制,class是待查询绘制的节点类名,会查询所有相同的类名。而limit是下面x和y的参考元素,故x和y就是class中元素参照limit祖先元素的偏移值。其更多属性参照与:https://github.com/liudongyun1215/wxml2canvas

let data = {
      //直接获取wxml数据
      list: [{
          type: 'wxml',
          class: '.share__canvas1 .draw_canvas',// draw_canvas指定待绘制的元素
          limit: '.share__canvas1',// 限定绘制元素的范围,取指定元素与它的相对位置
          x: 0,
          y: 0
        } ]
    }

好啦,这就是小谭今天要分享的内容,总结一下,其实这个功能看起来很麻烦,但是只要把思路理清楚在一步步实现就行。说个题外话,wx小程序官方自带组件的问题其实还是蛮坑的。所以,要慎用!血的教训,太惨了。

Logo

华为开发者空间,是为全球开发者打造的专属开发空间,汇聚了华为优质开发资源及工具,致力于让每一位开发者拥有一台云主机,基于华为根生态开发、创新。

更多推荐