微信辨图、支付寶小程序生成海報(bào)分享圖詳解

由于我們無(wú)法將小程序直接分享到朋友圈,但分享到朋友圈的需求又很多猿妈,業(yè)界目前的做法是利用小程序的 Canvas 功能生成一張帶有小程序碼的圖片吹菱,然后引導(dǎo)用戶下載圖片到本地后再分享到朋友圈。相信大家在繪制分享圖中應(yīng)該踩到 Canvas 的各種彩蛋(坑)了吧~

這里首先推薦一個(gè)開(kāi)源的組件:painter(通過(guò)該組件目前我們已經(jīng)成功在支付寶小程序上也應(yīng)用上了分享圖功能)

咱們不多說(shuō)彭则,直接上手就是干鳍刷。


0.png

首先我們新增一個(gè)自定義組件,在該組件的json中引入painter

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

然后組件的WXML (代碼片段在最后)

<view class="share-wrap" wx:if="{{visible}}" catchtouchmove="preventDefault">
  <view class="share-back"></view>
  <view class="share-container">
    <view class="close" bindtap="handleClose"></view>
    <image mode="widthFix" src="{{sharePath}}" class="share-image" />
    <view class="share-tips">保存圖片俯抖,叫伙伴們來(lái)參與吧</view>
    <view class="save-btn" bindtap="handlePhotoSaved"></view>
  </view>
</view>
<painter style="position: absolute; top: -9999rpx;" palette="{{imgDraw}}" bind:imgOK="onImgOK" />

接著組件的WXSS (代碼片段在最后)

.share-wrap {
  width: 100%;
}

.share-back {
  width: 100%;
  height: 100%;
  background: rgba(0, 0, 0, 0.6);
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  bottom: 0;
  z-index: 888;
}

.share-container {
  width: 100%;
  background: #FFF;
  position: fixed;
  bottom: 0;
  left: 0;
  right: 0;
  z-index: 999;
}

.close {
  width: 30rpx;
  height: 30rpx;
  overflow: hidden;
  position: absolute;
  right: 64rpx;
  top: 64rpx;
}

.close::after {
  transform: rotate(-45deg);
}

.close::before {
  transform: rotate(45deg);
}

.close::before,
.close::after {
  content: '';
  position: absolute;
  height: 3rpx;
  width: 100%;
  top: 50%;
  left: 0;
  margin-top: -2rpx;
  background: #9C9C9C;
}

.share-image {
  width: 420rpx;
  margin: 66rpx auto 0;
  display: block;
  border-radius: 16rpx;
  box-shadow: 0px 4rpx 8px 0px rgba(0, 0, 0, 0.1);
}

.share-tips {
  width: 100%;
  text-align: center;
  color: #3C3C3C;
  font-size: 28rpx;
  margin: 32rpx 0;
}

.save-btn {
  width: 336rpx;
  height: 96rpx;
  margin: 0 auto 94rpx;
  background: url('https://qiniu-image.qtshe.com/20190506save-btn.png') center center;
  background-size: 100% 100%;
}

重點(diǎn)來(lái)了 JS (代碼片段在最后)

Component({
  properties: {
    //屬性值可以在組件使用時(shí)指定
    isCanDraw: {
      type: Boolean,
      value: false,
      observer(newVal, oldVal) {
        newVal && this.drawPic()
      }
    }
  },
  data: {
    imgDraw: {}, //繪制圖片的大對(duì)象
    sharePath: '', //生成的分享圖
    visible: false
  },
  methods: {
    handlePhotoSaved() {
      this.savePhoto(this.data.sharePath)
    },
    handleClose() {
      this.setData({
        visible: false
      })
    },
    drawPic() {
      if (this.data.sharePath) { //如果已經(jīng)繪制過(guò)了本地保存有圖片不需要重新繪制
        this.setData({
          visible: true
        })
        this.triggerEvent('initData') 
        return
      }
      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: wx.getStorageSync('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: wx.getStorageSync('nickName') || '青團(tuán)子',
              css: {
                top: '532rpx',
                fontSize: '28rpx',
                left: '375rpx',
                align: 'center',
                color: '#3c3c3c'
              }
            },
            {
              type: 'text',
              text: `邀請(qǐng)您參與助力活動(dòng)`,
              css: {
                top: '576rpx',
                left: '375rpx',
                align: 'center',
                fontSize: '28rpx',
                color: '#3c3c3c'
              }
            },
            {
              type: 'text',
              text: `宇宙最萌藍(lán)牙耳機(jī)測(cè)評(píng)員`,
              css: {
                top: '644rpx',
                left: '375rpx',
                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: '生成分享圖失敗输瓜,請(qǐng)刷新頁(yè)面重試'
      })
    },
    onImgOK(e) {
      wx.hideLoading()
      this.setData({
        sharePath: e.detail.path,
        visible: true,
      })
      //通知外部繪制完成,重置isCanDraw為false
      this.triggerEvent('initData') 
    },
    preventDefault() { },
    // 保存圖片
    savePhoto(path) {
      wx.showLoading({
        title: '正在保存...',
        mask: true
      })
      wx.saveImageToPhotosAlbum({
        filePath: path,
        success: (res) => {
          wx.showToast({
            title: '保存成功',
            icon: 'none'
          })
          setTimeout(() => {
            this.setData({
              visible: false
            })
          }, 300)
        },
        fail: (res) => {
          wx.getSetting({
            success: res => {
              let authSetting = res.authSetting
              if (!authSetting['scope.writePhotosAlbum']) {
                wx.showModal({
                title: '提示',
                content: '您未開(kāi)啟保存圖片到相冊(cè)的權(quán)限,請(qǐng)點(diǎn)擊確定去開(kāi)啟權(quán)限尤揣!',
                success(res) {
                  if (res.confirm) {
                    wx.openSetting()
                  }
                }
              })
              }
            }
          })
          setTimeout(() => {
            wx.hideLoading()
            this.setData({
              visible: false
            })
          }, 300)
        }
      })
    }
  }
})

如此一個(gè)繪制分享圖的自定義組件就完成啦搔啊。

效果圖如下:

0.jpeg

tips:

  • 暫不支持繪制圖片 圓角為:10rpx 0rpx 0rpx 0rpx 類似的。
  • 文字居中實(shí)現(xiàn)可以看下我代碼片段
  • 文字換行實(shí)現(xiàn)(maxLines)只需要設(shè)置寬度芹缔,maxLines如果設(shè)置為1坯癣,那么一行超出將會(huì)展示為省略號(hào)
    當(dāng)然如果想支持四個(gè)圓角的 試試 把Pen.js文件78行的_doClip方法重寫(xiě),代碼:
_doClip(borderRadius, width, height) {
    if (borderRadius && width && height) {
      let border = borderRadius.split(' ')
      let r1 = 0
      let r2 = 0
      let r3 = 0
      let r4 = 0
      if (border.length==1){
        r1 = r2 = r3 = r4 = Math.min(border[0].toPx(), width / 2, height / 2);
      }else{
        r1 = Math.min(border[0] == 0 ? 0 : border[0].toPx(), width / 2, height / 2);
        r2 = Math.min(border[1] == 0 ? 0 : border[1].toPx(), width / 2, height / 2);
        r3 = Math.min(border[2] == 0 ? 0 : border[2].toPx(), width / 2, height / 2);
        r4 = Math.min(border[3] == 0 ? 0 : border[3].toPx(), width / 2, height / 2);
      }
      //const r = Math.min(borderRadius.toPx(), width / 2, height / 2);
      // 防止在某些機(jī)型上周邊有黑框現(xiàn)象最欠,此處如果直接設(shè)置 setFillStyle 為透明示罗,在 Android 機(jī)型上會(huì)導(dǎo)致被裁減的圖片也變?yōu)橥该鳎?iOS 和 IDE 上不會(huì)
      // setGlobalAlpha 在 1.9.90 起支持,低版本下無(wú)效芝硬,但把 setFillStyle 設(shè)為了 white蚜点,相對(duì)默認(rèn)的 black 要好點(diǎn)
      this.ctx.setGlobalAlpha(0);
      this.ctx.setFillStyle('white');
      this.ctx.beginPath();
      this.ctx.arc(-width / 2 + r1, -height / 2 + r1, r1, 1 * Math.PI, 1.5 * Math.PI);
      this.ctx.lineTo(width / 2 - r2, -height / 2);
      this.ctx.arc(width / 2 - r2, -height / 2 + r2, r2, 1.5 * Math.PI, 2 * Math.PI);
      this.ctx.lineTo(width / 2, height / 2 - r3);
      this.ctx.arc(width / 2 - r3, height / 2 - r3, r3, 0, 0.5 * Math.PI);
      this.ctx.lineTo(-width / 2 + r4, height / 2);
      this.ctx.arc(-width / 2 + r4, height / 2 - r4, r4, 0.5 * Math.PI, 1 * Math.PI);
      this.ctx.closePath();
      this.ctx.fill();
      // 在 ios 的 6.6.6 版本上 clip 有 bug,禁掉此類型上的 clip拌阴,也就意味著绍绘,在此版本微信的 ios 設(shè)備下無(wú)法使用 border 屬性
      if (!(getApp().systemInfo &&
          getApp().systemInfo.version <= '6.6.6' &&
          getApp().systemInfo.platform === 'ios')) {
        this.ctx.clip();
      }
      this.ctx.setGlobalAlpha(1);
    }
  }

主要是把borderRadius屬性Split為多個(gè)變量,然后一個(gè)一個(gè)判斷有沒(méi)有值迟赃。
使用方法(要么只給一個(gè)值陪拘,要么四個(gè)值都給):

borderRadius: '16rpx'
borderRadius: '16rpx 0 0 16rpx'

gitHub地址:https://github.com/Kujiale-Mobile/Painter
代碼片段:https://developers.weixin.qq.com/s/jiEZu4m17z9b
因?yàn)樯婕熬W(wǎng)絡(luò)圖片,代碼片段設(shè)置不了downloadFile合法域名纤壁,建議真機(jī)開(kāi)啟調(diào)試模式左刽,開(kāi)發(fā)者工具 詳情里開(kāi)啟不校驗(yàn)合法域名。

附上painter可視化編輯代碼工具:點(diǎn)我直達(dá)

最最后: 點(diǎn)個(gè)關(guān)注唄

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末酌媒,一起剝皮案震驚了整個(gè)濱河市欠痴,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌秒咨,老刑警劉巖喇辽,帶你破解...
    沈念sama閱讀 222,183評(píng)論 6 516
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異雨席,居然都是意外死亡菩咨,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,850評(píng)論 3 399
  • 文/潘曉璐 我一進(jìn)店門(mén)陡厘,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)抽米,“玉大人,你說(shuō)我怎么就攤上這事雏亚∮酰” “怎么了摩钙?”我有些...
    開(kāi)封第一講書(shū)人閱讀 168,766評(píng)論 0 361
  • 文/不壞的土叔 我叫張陵罢低,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我,道長(zhǎng)网持,這世上最難降的妖魔是什么宜岛? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 59,854評(píng)論 1 299
  • 正文 為了忘掉前任,我火速辦了婚禮功舀,結(jié)果婚禮上萍倡,老公的妹妹穿的比我還像新娘。我一直安慰自己辟汰,他們只是感情好列敲,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,871評(píng)論 6 398
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著帖汞,像睡著了一般戴而。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上翩蘸,一...
    開(kāi)封第一講書(shū)人閱讀 52,457評(píng)論 1 311
  • 那天所意,我揣著相機(jī)與錄音,去河邊找鬼催首。 笑死扶踊,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的郎任。 我是一名探鬼主播秧耗,決...
    沈念sama閱讀 40,999評(píng)論 3 422
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼涝滴!你這毒婦竟也來(lái)了绣版?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 39,914評(píng)論 0 277
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤歼疮,失蹤者是張志新(化名)和其女友劉穎杂抽,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體韩脏,經(jīng)...
    沈念sama閱讀 46,465評(píng)論 1 319
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡缩麸,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,543評(píng)論 3 342
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了赡矢。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片杭朱。...
    茶點(diǎn)故事閱讀 40,675評(píng)論 1 353
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖吹散,靈堂內(nèi)的尸體忽然破棺而出弧械,到底是詐尸還是另有隱情,我是刑警寧澤空民,帶...
    沈念sama閱讀 36,354評(píng)論 5 351
  • 正文 年R本政府宣布刃唐,位于F島的核電站羞迷,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏画饥。R本人自食惡果不足惜衔瓮,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 42,029評(píng)論 3 335
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望抖甘。 院中可真熱鬧热鞍,春花似錦、人聲如沸衔彻。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 32,514評(píng)論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)艰额。三九已至昼接,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間悴晰,已是汗流浹背慢睡。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,616評(píng)論 1 274
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留铡溪,地道東北人漂辐。 一個(gè)月前我還...
    沈念sama閱讀 49,091評(píng)論 3 378
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像棕硫,于是被迫代替她去往敵國(guó)和親髓涯。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,685評(píng)論 2 360