大數據

打造小程序版本公號和自託管的公號(3):為miniblog接入markdown和增強的一物一碼

本文關鍵字:微信一物一碼,一文一碼,小程序碼轉為普通二維碼

在《打造小程序版本公號和自託管的公號2》中我們講到了miniblog的初級搭建和定製,這裡繼續:

加入markdown編輯

前面說到miniblog的8個函數中,前6個函數可以整合,剩下synservice,synctoken不必整合。可以丟棄或保留(保留使用它的意義不甚大,這種同步結果和過程比較曲折,體驗不好,要使用它,記得syncservice/index.js/function syncWechatPosts(isUpdate) 中應該 let data = { currentOffset: 0, maxSyncCount: 由10改為1000 } ,同時提醒用戶把該函數超時時間設置大一點。 否則很難有正確結果。我120數據用了8秒。不要太頻繁調用這個函數,免費額度會減少。也不要搞按時自動觸發。這底下是因為那個函數內,調用公號素材庫未發佈文章一次只能取到20條,循環獲取就是maxsynccount指定的最大結果)。丟棄的情況下,我們則需要依賴內部的發佈文章機制,由於手機實在不好發文作富文本修飾或輸入(除非chromebook,apple arm macbook真的廣泛用起來了,人們用它辦公和文字生產了),粘貼複製還是可以的,所以最好是markdown的那套。目前miniblog的那個編輯器可以發markdown前端也能通過toxml渲染,但是測試了一下,不能修改和更新文章。

首先,加入miniblog的編輯文章功能。mini-blog-d02344fe6c6b347057983edd1ef6b7450f88fbcc這個rev刪掉了發文功能(審核問題刪了。),去它的上個版本把文件下載回來修改相關wxml,js調用加進去。然後是把富文本編輯器定製成markdown:

miniprogram/pages/admin/article/article.js中:
savePost: async function (e) 函數內:
contentType: "markdown",   //這裡由html改為markdown
content: res.text,  //這裡由res.html改為text
getContent: function () 函數內:
resolve(res.text)

miniprogram/pages/detail/detail.js中:let content = app.towxml(postDetail.result.content, 'markdown');

小程序首頁和文章詳情也都是調用toxml的地方,實際上,小程序首頁如果文章比較多下拉後返回上面很費事,你可以順便做個添加一個回到頂端,wx.pageScrollTo({scrollTop: 0,duration: 300})。由於源碼中toxml是放到src根下的,你還可以把toxml放進miniprogram/component文件夾內,這裡是放小程序組件的地方(由於本地的js版本不一,編譯miniprogram最好是本地進行,提取dist下生成的用。這也是前面文章提倡就地npm install編譯的道理),移動後修改相關路徑(component json和miniprogram/app.js中)。接下來會談到把海報生成poster組件也放進來。

加入增強的一物一碼

小程序實際上它也是web原理的page app,有各種路徑和調用參數,(IDE左下角可以看到),而二維碼是一種編碼解碼機制,的背後要麼是某段文字要麼是某個網址,工作原理是經過圖像掃描,編碼解碼得出碼後的結果。為app所用。微信支持三種為小程序生成二維碼的API,可以為小程序本身和小程序各種頁面和帶參數的頁面調用生成二維碼。即所謂支持一物一碼,這裡是文章,所以是一文一碼。

miniblog中有一個海報生成,裡面就有二維碼生成,它被放在了前端文章詳情頁,miniblog用的是api中的getunlimit(),可以為/page/detail/detail?id=blogid形式的帶參頁面生成對應小程序碼,如果有100篇文章可以生成100個二維碼。這種api生成的二維碼是小程序樣式的。較普通方塊二維碼有些缺陷(比如它難掃,而且這種小程序碼中間一個大大的logo很佔位置),最重要的問題是:它背後沒有一個https打頭的url:微信後臺對其一物一碼的綁定url,雖然它是頁面但其實它是小程序頁面不是https,僅限該miniblog小程序內綁定,我們需要把mini/index.js/getunlimit()換成createqrcode(較getunlimit和get,這個能得到普通二維碼。get和createqrcode各有5W多的限額共10夠用):

async function addPostQrCode(event) {
  //let scene = 'timestamp=' + event.timestamp;
  let result = await cloud.openapi.wxacode.createQRCode({
    //scene: event.postId,
    path: 'pages/detail/detail?id=' + event.postId,
    width: 280   //結果得到的從280到1280,我這裡只要最小的
  })
  .....
}

這樣就得到了普通二維碼圖片(中間LOGO,底下有一個提示語掃碼使用小程序的提示)和帶https的微信掃碼綁定機制,我們把它叫作decodeqrcodeurl。得到這個,我們可以為其重新編碼生成二維碼,這樣再處理之後的二維碼有什麼用呢,比如,用we-app-qrcode之類的組件再處理,不僅可以將提示語和LOGO去掉,而且可以用草料等工具定製美化。還可以可以壓縮其體積,生成base64,供同一份內容的多次外發的文章腳部鏈接小程序二維碼使用。真正讓一物一碼做到極致。

在mini/index.js中,我們加入重新解碼的邏輯:

頭部加入:
const decodeImage = require('jimp').read
const qrcodeReader = require('qrcode-reader')


async function addPostQrCode(event)前加入:
//解碼二維碼buffer
function qrDecode(data,callback){
  decodeImage(data,function(err,image){
      if(err){
          callback(false);
          return;
      }
      let decodeQR = new qrcodeReader();
      decodeQR.callback = function(errorWhenDecodeQR, result) {
          if (errorWhenDecodeQR) {
              callback(false);
              return;
          }
          if (!result){
              callback(false);
              return;
          }else{
              callback(result.result)
          }
      };
      decodeQR.decode(image.bitmap);
  });
}

async function addPostQrCode(event)中加入:
async function addPostQrCode(event) {
....
  if (result.errCode === 0) {

    qrDecode(result.buffer,function(urlcontent){
    console.log("decode:" + urlcontent);
  });
  .....
}

在mini下npm install -save jimp和qrcode-reader可以在package.json中加入:
 "dependencies": {
    .....
    "jimp": "^0.16.0",
    "qrcode-reader": "^1.0.4",
    .....
  }

miniprogram方面,文章詳情頁的分享小程序頁面本來就存在,拉取(海報中的)二維碼又涉及到服務端調用返回二維碼費資源,乾脆不交給用戶,將它做成admin page內供管理員編輯文章處用更合適。也可以達到同樣由用戶來生成二維碼的效果。還更可控,適用。比如,可以砍掉生成整個海報其它部分僅保留二維碼生成部分,然後轉移相關wxml,js函數調用,component定義(包括js中的初始data定義)到admin/article/articlelist頁(不要放在article/article,批量操作不現實),按鈕跟那些“展示”,“專題”,“標籤”小紅方塊放一起,當還要定製主邏輯函數,具體如下:

//utils/api.js中, function getNewPostsList(page, filter, orderBy) {}和function getPostsList(page, filter, isShow, orderBy, label) {}中,這二函數的_fields都加起:qrCode: true來,以便在articlelist.wxml中能:

<view class='cu-tag bg-red bg-{{item.qrCode == undefined?"red":"green"}} light' data-postqrcode="{{item.qrCode}}" data-postid="{{item._id}}" catchtap='onCreatePoster'>
  {{item.qrCode == undefined?"未生碼":"已生碼"}}
</view>

//然後是主函數:

onCreatePoster: async function (e) {
  let that = this;

  let postid = e.currentTarget.dataset.postid
  console.info(postid)
  let postqrcode = e.currentTarget.dataset.postqrcode
  console.info(postqrcode)
  let qrCode = await api.getReportQrCodeUrl(postqrcode);
  let qrCodeUrl = qrCode.fileList[0].tempFileURL
  console.info(qrCodeUrl)
  that.data.posterImageUrl = qrCodeUrl

  if (postqrcode == undefined || that.data.posterImageUrl == "") {
    let addReult = await api.addPostQrCode(postid)
    qrCodeUrl = addReult.result[0].tempFileURL
  } else {      
    that.setData({
      posterImageUrl: qrCodeUrl,
      isShowPosterModal: true    //model是模態對話框意思
    })
    return;      
  }

  let posterConfig = {
    width: 600,
    height: 600,
    backgroundColor: '#fff',
    debug: false
  }
  var blocks = []
  var texts = [];
  texts = [];
  var images = [
    {
      width: 560,
      height: 560,
      x: 20,
      y: 20,
      url: qrCodeUrl,//二維碼的圖
    }
  ];

  posterConfig.blocks = blocks;//海報內圖片的外框
  posterConfig.texts = texts; //海報的文字
  posterConfig.images = images;

  that.setData({ posterConfig: posterConfig }, () => {
    Poster.create(true);    //生成海報圖片
  });
  await that.onPullDownRefresh()

},

//你會發現列表是按createtime排的,utils/api.js中要改成timestamp,

if (orderBy == undefined || orderBy == "") {
  orderBy = "timestamp"
}

//然後utils/api.js中function getNewPostsList的檢索條件和index.js中的檢籤邏輯(記得把總體文字縮短否則idx6之後顯不出來,我是把已xxx全刪了僅保留未xxx)也加起來。

if (filter.qrcoded == 1) {
  where.qrCode = _.nin(["", 0, undefined])
}

if (filter.qrcoded == 2) {
  where.qrCode = _.in(["", 0, undefined])
}

//如果你還想把生成的一物一碼自動欠入各文章詳情頁內。,代替原來的onpostcreater()位置,那麼可以
showQrcode2: async function (e) {
  let that = this;
  let qrCode = await api.getReportQrCodeUrl(that.data.post.qrCode);
  let qrCodeUrl = qrCode.fileList[0].tempFileURL
  wx.previewImage({
    urls:  [qrCodeUrl],
    current: "一文一碼"
  })
},

整個過程依然都是在IDE模擬器中不斷的修改,調試,再調試(提一下,我用的IDE是deepin20商店中https://github.com/cytle/wechat_web_devtools編譯的,這個IDE騰訊官方沒有列出為支持項)。要注意服務端的在函數後臺看日誌,IDE只能看出客戶端的輸出,由於上面是加入到服務端函數後端的,因此調試結果console.log("decode:" + urlcontent);在IDE端是看不到的(除非你打開IDE中的函數調用日誌)。突然發現小程序用於實踐很微粒化。一天一個微程序,像jupyter一樣每天練習,持之以恆,可以積累下大量的語言和項目開發經驗。


(此處不設回覆,掃碼到微信參與留言,或直接點擊到原文)

qrcode.png

Leave a Reply

Your email address will not be published. Required fields are marked *