对于上一部分,如果共享内容是异步生成的,那么共享的图片往往是动态的(非固定的本地资源或网络资源)。
对于图片的动态分享定制小程序,通常有两种解决方案:
依靠服务器的图像处理功能灵活合成需要的图像,缺点很明显。图片处理会消耗过多的服务器资源,影响服务器的整体吞吐量
在客户端本地使用canvas绘制内容 开发小程序 ,最后通过wx.canvasToTempFilePath保存临时图片路径供分享。这种方式的缺点:兼容性不够好,可能会遇到各种bug
在第一次开发过程中,我选择了canvas来绘制和分享图片。主要步骤如下:
这里有个思路:canvas块不应该影响布局不可见,但是实践后发现不能使用display: none;或不透明度:0;这边走。终于想出了一个可行的办法:用视图容器包裹画布,然后将视图的样式设置为height:0;溢出:隐藏;
这种方式的优点是不依赖服务器定制小程序,节省了服务器的性能开销,但也有一个致命的缺点:图片生成是异步的,与onShareAppMessage需要同步返回数据相冲突。
为了解决这个问题,所采用的解决方案是当影响共享镜像的因素发生变化时立即重新生成,当失败时需要考虑替换镜像。由于频繁使用canvas绘制和保存图片定制小程序,这种做法可能会影响小程序的运行流畅度。
最后贴上输入框内容动态生成共享图片的核心代码:
App({
drawLock: false, // 避免同时对一个canvas进行操作
shareImageCache: {}, // 尽可能优化
drawShareImage: function (canvasId, ctx, text) {
if (this.drawLock) {
return;
}
this.drawLock = true;
let that = this;
let cacheKey = util.hash(text);
if (this.shareImageCache[cacheKey]) {
return Promise.resolve(this.shareImageCache[cacheKey]);
}
ctx.clearRect(0, 0, 500, 400);
return new Promise(resolve, reject => {
ctx.setFillStyle('#333333');
ctx.setFontSize(40);
ctx.fillText(text, 20, 60);
ctx.draw(true, () => {
promisify(wx.canvasToTempFilePath)({
canvasId: canvasId
}).then(res => {
this.drawLock = false;
that.shareImageCache[cacheKey] = res.tempFilePath;
resolve(res.tempFilePath);
}).catch(err => {
this.drawLock = false;
reject(err);
});
});
});
}
});
Page({
data: {
canvasId: 'share-canvas',
},
shareImagePath: null,
onLoad: function () {
this.ctx = wx.createCanvasContext(this.data.canvasId);
this.drawShare();
},
onInput: function () {
if (this.preInputTimer) {
clearTimeout(this.preInputTimer);
}
this.preInputTimer = setTimeout(() => {
this.drawShare();
}, 1000); // 这个数字最好是比一般人连续输入时间间隔大一丢丢
},
drawShare: function () {
return app.drawShareImage(this.data.canvasId, this.ctx, e.detail.value).then(path => {
this.shareImagePath = path;
}).catch(err => {
logger.error(err);
});
}
});
以上代码是我自己的小程序代码中提取的部分内容。绘制行为放置在应用程序中以与其他页面共享。
上面是一个极端的例子 小程序外包开发 ,因为用户的输入是实时反馈到共享图像的。如果您考虑产品级别的变通方法,可能会有更好的想法和解决方案。
原创博客
发现、改变
探知、求新
共享,感恩一路相伴
昱远品牌形象已完成全面升级
点击访问新官网