评论

如何实现快速生成朋友圈海报分享图

如何快速实现朋友圈海报分享图~

由于我们无法将小程序直接分享到朋友圈,但分享到朋友圈的需求又很多,业界目前的做法是利用小程序的 Canvas 功能生成一张带有小程序码的图片,然后引导用户下载图片到本地后再分享到朋友圈。相信大家在绘制分享图中应该踩到 Canvas 的各种(坑)彩dan了吧~

这里首先推荐一个开源的组件:painter(通过该组件目前我们已经成功在支付宝小程序上也应用上了分享图功能)

咱们不多说,直接上手就是干。

首先我们新增一个自定义组件,在该组件的json中引入painter

{
  "component": true,
  "usingComponents": {
    "painter": "/painter/painter"
  }
}

然后组件的WXML (代码片段在最后)

// 将该组件定位在屏幕之外,用户查看不到。
<painter style="position: absolute; top: -9999rpx;" palette="{{imgDraw}}" bind:imgOK="onImgOK" />

重点来了 JS (代码片段在最后)

Component({
  properties: {
    // 是否开始绘图
    isCanDraw: {
      type: Boolean,
      value: false,
      observer(newVal) {
        newVal && this.handleStartDrawImg()
      }
    },
    // 用户头像昵称信息
    userInfo: {
      type: Object,
      value: {
        avatarUrl: '',
        nickName: ''
      }
    }
  },
  data: {
    imgDraw: {}, // 绘制图片的大对象
    sharePath: '' // 生成的分享图
  },
  methods: {
    handleStartDrawImg() {
      wx.showLoading({
        title: '生成中'
      })
      this.setData({
        imgDraw: {
          width: '750rpx',
          height: '1334rpx',
          background: 'https://qiniu-image.qtshe.com/20190506share-bg.png',
          views: [
            {
              type: 'image',
              url: 'https://qiniu-image.qtshe.com/1560248372315_467.jpg',
              css: {
                top: '32rpx',
                left: '30rpx',
                right: '32rpx',
                width: '688rpx',
                height: '420rpx',
                borderRadius: '16rpx'
              },
            },
            {
              type: 'image',
              url: this.data.userInfo.avatarUrl || 'https://qiniu-image.qtshe.com/default-avatar20170707.png',
              css: {
                top: '404rpx',
                left: '328rpx',
                width: '96rpx',
                height: '96rpx',
                borderWidth: '6rpx',
                borderColor: '#FFF',
                borderRadius: '96rpx'
              }
            },
            {
              type: 'text',
              text: this.data.userInfo.nickName || '青团子',
              css: {
                top: '532rpx',
                fontSize: '28rpx',
                left: '375rpx',
                align: 'center',
                color: '#3c3c3c'
              }
            },
            {
              type: 'text',
              text: `邀请您参与助力活动`,
              css: {
                top: '576rpx',
                left: '375rpx',
                align: 'center',
                fontSize: '28rpx',
                color: '#3c3c3c'
              }
            },
            {
              type: 'text',
              text: `宇宙最萌蓝牙耳机测评员`,
              css: {
                top: '644rpx',
                left: '375rpx',
                maxLines: 1,
                align: 'center',
                fontWeight: 'bold',
                fontSize: '44rpx',
                color: '#3c3c3c'
              }
            },
            {
              type: 'image',
              url: 'https://qiniu-image.qtshe.com/20190605index.jpg',
              css: {
                top: '834rpx',
                left: '470rpx',
                width: '200rpx',
                height: '200rpx'
              }
            }
          ]
        }
      })
    },
    onImgErr(e) {
      wx.hideLoading()
      wx.showToast({
        title: '生成分享图失败,请刷新页面重试'
      })
      //通知外部绘制完成,重置isCanDraw为false
      this.triggerEvent('initData') 
    },
    onImgOK(e) {
      wx.hideLoading()
      // 展示分享图
      wx.showShareImageMenu({
        path:  e.detail.path,
        fail: err => {
          console.log(err)
        }
      })
      //通知外部绘制完成,重置isCanDraw为false
      this.triggerEvent('initData') 
    }
  }
})

那么我们该如何引用呢?

首先json里引用我们封装好的组件share-box
{
  "usingComponents": {
    "share-box": "/components/shareBox/index"
  }
}
以下示例为获取用户头像昵称后再生成图。
<button class="intro" bindtap="getUserInfo">点我生成分享图</button>
<share-box isCanDraw="{{isCanDraw}}" userInfo="{{userInfo}}"  bind:initData="handleClose" />
调用的地方:
const app = getApp()

Page({
  data: {
    isCanDraw: false
  },
  // 组件内部关掉或者绘制完成需重置状态
  handleClose() {
    this.setData({
      isCanDraw: !this.data.isCanDraw
    })
  },
  getUserInfo(e) {
    wx.getUserProfile({
      desc: "获取您的头像昵称信息",
      success: res => {
        const { userInfo = {} } = res
        this.setData({
          userInfo,
          isCanDraw: true // 开始绘制海报图
        })
      },
      fail: err => {
        console.log(err)
      }
    })
  }
})

最后绘制分享图的自定义组件就完成啦~效果图如下:

tips:

  • 文字居中实现可以看下代码片段
  • 文字换行实现(maxLines)只需要设置宽度,maxLines如果设置为1,那么超出一行将会展示为省略号

代码片段:https://developers.weixin.qq.com/s/J38pKsmK7Qw5

附上painter可视化编辑代码工具:点我直达,因为涉及网络图片,代码片段设置不了downloadFile合法域名,建议真机开启调试模式,开发者工具 详情里开启不校验合法域名进行代码片段的运行查看。
最后看下面大家评论问的较多的问题:downLoadFile合法域名在小程序后台 开发>开发设置里配置,域名为你图片的域名前缀 比如我文章里的图https://qiniu-image.qtshe.com/20190605index.jpg。配置域名时填写https://qiniu-image.qtshe.com即可。如果你图片cdn地址为https://aaa.com/xxx.png, 那你就配置https://aaa.com即可。
最后一次编辑于  2022-01-20  
点赞 125
收藏
评论

121 个评论

  • 白蛋
    白蛋
    2020-04-18

    您好,我能通过这个来实现 小程序特定页面(就小窗播放的视频view)画面的截取保存上传吗

    2020-04-18
    赞同
    回复 5
  • 许健
    许健
    2020-04-13

    你好,请问一定要下载到本地么?

    我canvas转变成img,获取到了temFilePath的路径,我直接赋值给了onShareAppMessage的imageUrl,但是没有生效。

    2020-04-13
    赞同
    回复 3
  • 在劫难逃的天真
    在劫难逃的天真
    2020-04-08

    楼主 绘制图片是异步的 如果我拿图片做canvas的背景图 然后绘制文本 但是因为图片是异步绘制 就会 导致图片绘制的慢 最后遮盖住了文本 怎么解决呢

    2020-04-08
    赞同
    回复 5
    • 拎壶冲^
      拎壶冲^
      2020-04-08
      贴下代码片段。我看下
      2020-04-08
      回复
    • 在劫难逃的天真
      在劫难逃的天真
      2020-04-08回复拎壶冲^
      2020-04-08
      回复
    • 在劫难逃的天真
      在劫难逃的天真
      2020-04-08回复拎壶冲^
      上面是绘制背景图 应该先执行  但是因为绘制图片是异步 最终是下面的文本先绘制完 然后图片绘制完 就导致图片遮盖住了文本
      2020-04-08
      回复
    • 在劫难逃的天真
      在劫难逃的天真
      2020-04-08回复拎壶冲^
      我们有自己的后台配置  样式 布局都是配置的 这个组件我看了  不太适合。。。
      2020-04-08
      回复
    • 拎壶冲^
      拎壶冲^
      2020-04-08
      不是用的 2d吧??
      2020-04-08
      回复
  • do-do
    do-do
    2020-04-05
    views: [
                {
                  type: 'image',
                  url: wx.getStorageSync('imageUrl') || 'https://default-avatar.png',
                  css: {
                    top: '0rpx',
                    left: '0rpx',
                    right: '0rpx',
                    width: '560rpx',
                    height: '558rpx',
                    borderRadius: '16rpx'
                  },
                },
    ]
    



    楼主,您好!上次绘制云存储的图片,通过您给的 wx.cloud.getTempFileURL({})这个函数实现了云存储ID,转换为图片的URL,可以实现图片绘制,谢谢!

    这次我遇到了 绘制图片的时候,设置图片的宽和高的时候,  较小的那个数值不是按照设置的数值绘制的,比如本例中(width: '560rpx',  height: '558rpx',) 宽是560rpx没问题,但是高只要设置小于宽的值都不会正确显示,我无论把高设置为 550rpx. 558rpx,绘制图片都一样,只有把高设置为560rpx,和宽一样才会正确显示,问下您遇到过这个问题吗?谢谢!
    




    2020-04-05
    赞同
    回复 5
    • 拎壶冲^
      拎壶冲^
      2020-04-07
      不会正确显示是?你设置和宽560 高200 然后截图看下。
      2020-04-07
      回复
    • do-do
      do-do
      2020-04-08回复拎壶冲^
      2020-04-08
      回复
    • do-do
      do-do
      2020-04-08回复拎壶冲^
      如图所示,宽:560 高:560 和高:559 一样;
      宽:560  高在420-558 保持不变;
      只有高在400才会减小。
      2020-04-08
      回复
    • 拎壶冲^
      拎壶冲^
      2020-04-09回复do-do
      因为 图片默认是aspectFill,你可以设置为:
      css: {
               
                      mode: “scaleToFill”
                    },
      2020-04-09
      1
      回复
    • 甲乙。
      甲乙。
      2020-06-20回复拎壶冲^
      如果mode想设置为aspectFit可以吗??
      2020-06-20
      回复
  • Keep real😇
    Keep real😇
    2020-03-14

    你好,生成图片过大怎么办

    2020-03-14
    赞同
    回复 1
    • 拎壶冲^
      拎壶冲^
      2020-03-16
      图大还是质量过大
      2020-03-16
      回复
  • do-do
    do-do
    2020-03-09

    楼主,您好!如下代码所示,将url设置为,https类型的网络图片可以正常加载,将url换成云开发中存储的图片会出错,

    报错如下:

    VM651:1 Failed to load local image resource /component/components/painter/cloud://xxxxXX/vision-test-image1583682357195.jpg 

     the server responded with a status of 500 (HTTP/1.1 500 Internal Server Error) 

    问下您是不是只能使用网络图片和本地图片,不可以使用云开发中存储的图片?

    谢谢楼主。

    {

                  type: 'image',
                  url: wx.getStorageSync('imageUrl') || 'https://qiniu-image.qtshe.com/default-avatar20170707.png',
                  css: {
                    top: '32rpx',
                    left: '30rpx',
                    right: '32rpx',
                    width: '688rpx',
                    height: '420rpx',
                    borderRadius: '16rpx'
                  },
                },
    
    2020-03-09
    赞同
    回复 11
    • 拎壶冲^
      拎壶冲^
      2020-03-10
      可以使用。
      2020-03-10
      回复
    • do-do
      do-do
      2020-03-10回复拎壶冲^
      您好!那我这边为啥会报如上错误?
      2020-03-10
      回复
    • 拎壶冲^
      拎壶冲^
      2020-03-10
      500是网络错误,你这边这个图片地址能展示到页面上么?我记得cloud的地址不是这样的,没搞过云开发不太清楚。。。。
      2020-03-10
      1
      回复
    • do-do
      do-do
      2020-03-10回复拎壶冲^
      图片本身在我小程序内可以正常展示的,但是用这个组件就会报错, 图片存储小程序自带的云存储中。
      2020-03-10
      回复
    • do-do
      do-do
      2020-03-11回复拎壶冲^
      这是云存储的 FileID:
      cloud://cloud-environment-name.6875-cloud-environment-name-1301043156/vision-test-image1578227244217.jpg   


      url:字段也是填的这个,但是会报错,是不是 没有权限获取该图片?
      2020-03-11
      回复
    查看更多(6)
  • 甲乙。
    甲乙。
    2020-02-28

    您好我想请教一下是否可以设置卡片生成文字两行显示且超出隐藏呢?

    2020-02-28
    赞同
    回复 14
    • 拎壶冲^
      拎壶冲^
      2020-02-28
      这个功能建议自己做文字截取,目前我们可以做到文字超出省略号
      2020-02-28
      回复
    • 甲乙。
      甲乙。
      2020-02-28回复拎壶冲^
      是否设置maxLines就可以?但是我设置为1或者设置宽度都不可以都没有效果呢?
      2020-02-28
      回复
    • 拎壶冲^
      拎壶冲^
      2020-02-28回复甲乙。
      设置宽度 并且设置maxLines为1说明超出这个宽度会省略号
      2020-02-28
      回复
    • 甲乙。
      甲乙。
      2020-02-28回复拎壶冲^
      刚好用上了,谢谢大佬的分享!
      2020-02-28
      回复
    • 拎壶冲^
      拎壶冲^
      2020-02-28回复甲乙。
      👌
      2020-02-28
      回复
    查看更多(9)
  • 曹孟良
    曹孟良
    2020-02-22

    膜拜!

    2020-02-22
    赞同
    回复
  • 倾紫
    倾紫
    2020-02-14

    想问下为什么views里面的东西,ios上没生成

    2020-02-14
    赞同
    回复 1
    • 拎壶冲^
      拎壶冲^
      2020-02-15
      写个代码片段??什么问题
      2020-02-15
      回复
  • Qiu (吉²)
    Qiu (吉²)
    2020-02-12

    请问这个data-ptpid是什么啊?起到什么作用?

    2020-02-12
    赞同
    回复 1
    • 拎壶冲^
      拎壶冲^
      2020-02-12
      这是我的业务代码。没用的。你删掉即可。这是我们做自定义埋点的。
      2020-02-12
      回复

正在加载...

登录 后发表内容