引言
最近有一個生成很多小程式碼的需求,生成的小程式碼還要嵌入在指定的圖片模板上,就去找輪子,沒找到合適的輪子。。無奈之下就決定去擼一個。目前已經完成併發布npm。
Github:github.com/Jon-Millent…
需求
如下圖
- 生成帶引數的小程式二維碼
- 要指定尺寸和位置到模板圖上
- 要批量生成若干張
開始幹活
生成帶引數的小程式二維碼
通過官方文件,列出了生成小程式二維碼的三種模式
-
createWXAQRCode
獲取小程式二維碼
,適用於需要的碼數量較少的業務場景。通過該介面生成的小程式碼,永久有效,有數量限制。官方說明 -
getWXACode
獲取小程式碼
,適用於需要的碼數量較少的業務場景。通過該介面生成的小程式碼,永久有效,有數量限制。 官方說明 -
getWXACodeUnlimit
獲取小程式碼
,適用於需要的碼數量極多的業務場景。通過該介面生成的小程式碼,永久有效,數量暫無限制。 官方說明
這些介面都要通過access_token
來換取。讓我們造個類
let AngerWechat = require('anger-wechat') // 微信操作輔助庫(自己寫的)
class miniQrcode {
// 存放三種模式的介面
constructor(config) {
this.mode = {
'getWXACode': 'https://api.weixin.qq.com/wxa/getwxacode',
'getWXACodeUnlimit': 'https://api.weixin.qq.com/wxa/getwxacodeunlimit',
'createWXAQRCode': 'https://api.weixin.qq.com/cgi-bin/wxaapp/createwxaqrcode',
}
// 初始化微信輔助庫
this.$wx = new AngerWechat({
appId: this.config.appId, // appId 必傳
appSecret: this.config.appSecret, // appSecret 必傳
})
// 臨時資料存放檔案,用於存放access_token,因為access_token有2個小時的生存期,避免重複獲取
this.databasePath = path.join(__dirname, '../', 'database.json')
}
}
複製程式碼
實現核心方法
// 生成核心方法
async getWxQrcodeInfo(concatConfig){
// 獲取已經存放的檔案裡的access_token,如果有的話並且有效的話就不用再掉介面
let innerDatabase = this.getDatabase()
// 如果本地的資料沒有access_token 或者超過2個小時 就去請求獲取
if(!innerDatabase.access_token || ((new Date().getTime() - innerDatabase.create_time) > 7200000) ) {
let accessInfo = await this.$wx.getGlobalAccessToken()
// 獲取access_token然後寫入檔案
// 具體程式碼省略
}
// 獲取到access_token去請求介面
let qrcodeInfo = await this.postMan(
this.getApiUrl(innerDatabase.access_token, concatConfig.mode), // 根據mode來區呼叫介面
concatConfig.config // 使用者傳的引數
)
let returnData = {
}
if(qrcodeInfo.type.indexOf('image') !== -1) { //型別是圖片的就是獲取成功了
// 請求成功 儲存圖片
returnData = {
code: 200,
image: qrcodeInfo.data,
error: null
}
} else {
returnData = {
code: 500,
error: JSON.stringify(qrcodeInfo.data.toString()),
image: null
}
}
return returnData
}
複製程式碼
寫好後讓我們測試一下
let qrocode = new miniQrcode({
appId: 'xxx',
appSecret: 'xxx'
});
let info = await qrocode.getWxQrcodeInfo({
mode: 'getWXACode',
config: {
path: `pages/index/main?id=123456`
},
})
fs.writeFileSync(`./output-juejin-test1.png`, info.image, 'utf8');
複製程式碼
效果:
如何測試引數?我在這個已經發布的小程式裡面加了個彩蛋,就是長按紅色圈出區域兩次
即可調出控制檯看引數
將二維碼合成到模板圖片裡面
這個操作依賴於sharp
庫
const sharp = require('sharp');
class miniSharp {
constructor(templateUrl){
this.templateUrl = templateUrl
}
// 重置圖片大小
async resizeQrcode(imageBuffer, config){
return new Promise(resolve => {
sharp(imageBuffer).resize(config.width, config.width).toBuffer().then(function(outputBuffer) {
resolve(outputBuffer)
});
})
}
// 合併圖片
async concatImage(buffer, config){
return new Promise(resolve => {
sharp(this.templateUrl)
.overlayWith(buffer, {
top: config.top,
left: config.left
}).toBuffer().then(function(outputBuffer) {
resolve(outputBuffer)
});
})
}
// 主函式
async renderImage(qrcodeBuffer, config){
let resizeQrcodeBuffer = await this.resizeQrcode(qrcodeBuffer, config)
let concatQrocdeBuffer = await this.concatImage(resizeQrcodeBuffer, config)
return concatQrocdeBuffer
}
}
module.exports = miniSharp
複製程式碼
測試一下
let qrocode = new miniQrcode({
appId: 'xxxx',
appSecret: 'xxx'
});
let mySharp = new miniSharp('./template.png');
let info = await qrocode.getWxQrcodeInfo({
mode: 'getWXACode',
config: {
path: `pages/index/main?id=123456`
},
})
let renderBuffer = await mySharp.renderImage(info.image, // 二維碼圖片的 buffer 陣列
{
width: 200, // 重新設定二維碼寬度
left: 362, // x軸偏移
top: 53 // y軸偏移
})
fs.writeFileSync(`./output-juejin-test1.png`, renderBuffer, 'utf8');
複製程式碼
批量處理
正常情況下,批量生成100
張需要62.556秒
,平均每張需要0.62556秒
,1萬張大概需要 1.73小時
。 批量示例程式碼
關於除錯
使用微信開發者工具可以進行模擬引數除錯
測試介面
這裡我提供了一個測試介面,可以帶引數生成線上的小程式碼,用來除錯
[get]
http://wx.toolos.cc
引數
mode
必傳 [createWXAQRCode | getWXACode | getWXACodeUnlimit] 之一
注意
- 其他引數對應上面的文件的
mode
對應的引數,path
或者page
需要encodeURIComponent
一下 - 目前小程式只有一個路徑
pages/index/main
- 線上伺服器配置低
示例
http://wx.toolos.cc/?mode=createWXAQRCode&path=pages%2Findex%2Fmain
複製程式碼
關於引數模式
createWXAQRCode & getWXACode
這兩種生成的引數,生成二維碼數量有限,引數直接跟在path路徑後面,例如:
let info = await qrocode.getWxQrcodeInfo({
mode: 'createWXAQRCode',
config: {
page: `pages/index/main?sgr=521314&i=loveyou`
},
})
複製程式碼
getWXACodeUnlimit
這個可以生成無限個,但是隻能攜帶有侷限性的引數scene
,在這裡推薦一種解析方式 key:value-key:value
let info = await qrocode.getWxQrcodeInfo({
mode: 'getWXACodeUnlimit',
config: {
page: `pages/index/main`,
scene: 'i:loveyou-sgr:521314'
},
})
複製程式碼
解析示例
onLoad (query) {
// scene 需要使用 decodeURIComponent 才能獲取到生成二維碼時傳入的 scene
this.scene = decodeURIComponent(query.scene)
this.queryJson = JSON.stringify(query)
// 嘗試解析 scene 格式: shop:1-id:2
try {
let oneArr = this.scene.split('-')
let twoJson = {}
for(let i=0; i<oneArr.length; i++) {
let target = oneArr[i].split(':')
twoJson[target[0]] = target[1]
}
this.twoJson = JSON.stringify(twoJson)
} catch(e) {
this.twoJson = e
}
},
複製程式碼
在開發者工具中例如下面模擬