最近开发微信小程序,记录一些重要的知识点。部分内容引用自微信官方文档。
概览部分引用自《微信开放文档》1
网页开发的渲染线程和脚本线程是互斥的,因此长时间运行脚本可能导致页面失去响应。
在小程序中,渲染和脚本分别运行在不同的线程中。
逻辑层运行在 JSCore 中,并没有一个完整浏览器对象,因而缺少相关的DOM API和BOM API。这导致一些常用库(jQuery、 Zepto 等),在小程序中是无法运行的。同时 JSCore 的环境同 NodeJS 环境也是不尽相同,所以一些 NPM 的包在小程序中也是无法运行的1。
当用户点击右上角胶囊按钮关闭小程序,或者按了设备 Home 键离开微信时,小程序并没有直接销毁,而是进入了后台状态;
当用户再次进入微信或再次打开小程序,小程序又会从后台进入前台。
需要注意的是:只有当小程序进入后台一定时间,或者系统资源占用过高,才会被真正的销毁。
在调试过程中,安卓小程序在后台显示为与App类似的实际view,也就是说安卓用户可以手动销毁小程序,但在IOS系统上,小程序不显示。这一点还有待考证。
由于视图层和逻辑层分开,有频繁用户交互的效果会比较卡顿。需要先将用户在视图层的event传进逻辑层,逻辑层处理完成之后通过setData()再传入视图层。需要两次通信+一次渲染。setData 渲染也会阻塞其它脚本执行,导致了整个用户交互的动画过程会有延迟。
因此WXS的使用的思路是减少通信的次数,让部分逻辑代码在视图层运行。
目前微信内分享常见三种形式,推荐到好物圈,朋友圈分享,微信好友/群分享
好物圈以插件形式存在,下文不具体涉及。
朋友圈分享,目前来看大多用画图来完成。由于微信没有提供直接分享朋友圈的接口,因此各路神通想出了:生成图片保存相册,转发朋友圈,扫图中小程序码的“三段跳”解决方案。这样在海报样式上能做更大的文章。比如插入用户信息,产品的信息,更酷炫的设计等等。
除了朋友圈分享这种方式,微信好友/群内分享也很常见。微信提供了很多API,其中包括监听页面内转发事件。在转发的过程中默认截取当前页面为转发图。如果想要得到更酷炫的转发图,也需要用到canvas画图来生成。
微信在Page中提供了onShareAppMessage的事件处理函数,监听用户点击页面内转发按钮。该函数返回一个对象,用于自定义转发内容:
{
title: //标题
path: //转发路径
imgUrl: //自定义图片路径,可以是本地文件路径、代码包文件路径或者网络图片路径
}
因此,自然而然可以想到,在imgUrl上做文章。需要动态生成一张图片,并保存其url。到此,思路便比较清晰了:生成图片可用canvas绘图,并利用微信提供的API - wx.canvasToTempFilePath 得到本地图片url。
分享图生成的画图方法在页面的生命周期中位置如下:
页面视图wxml文件中,button绑定onShareAppMessage()
方法。同时设置canvas画布。利用wxss设置样式移到可见范围之外。
页面初次加载(onLoad)时,获取需要分享信息数据。可能同时包含有文字和图片信息。若图片来自网络,则会先下载到本地为画图备用。需要利用wx.getImageInfo()
,获得该图片的本地url,在success回调函数中进行下一步处理画图。可以将该API包进一个Promise
对象中返回,便于其他模块处理网络图片的链式调用和后续处理。
创建canvas上下文,利用canvas相关方法画图。关键的draw()方法有三个重要参数,第一个表示是否保留画布之前内容,第二个为绘制完的回调函数。在回调函数中调用wx.canvasToTempFilePath()
,把当前画布指定区域的内容导出生成指定大小的图片。第三个为需要作用于的this对象。这一点很重要,因为需要在wx.canvasToTempFilePath()
成功后,在其success回调中,将生成图片的url设置为page的全局变量。这样能在page作用域内,将生成图片的url设置到事件处理函数onShareAppMessage()
当中。
为什么不隐藏canvas,设置display:hidden
隐藏会导致绘制失效
为什么在页面加载时就生成图片,而不是点击分享按钮后生成图片
在页面事件onShareAppMessage()
运行时,只有按规则返回具有对应参数的对象时,才能成功弹出分享到微信好友界面。(作者尝试通过Promise
异步返回,但由于wx限制,若返回Promise
对象便不能识别。)然而,在画图过程中调用的几个API均为异步方法,因此对于page页面的事件,无法做到先点击share button,触发onShareAppMessage()
后,在该方法内调用其他异步绘图方法。这样无法得到新绘制图的url。
关于2真的做不到吗?我不是很相信
具体见4、同类小程序分享调研
第一次点分享按钮图片不是我想要的,退出再点击一次就好了
说明异步画图的url还没设置进去,用户就点击了分享按钮。这个时候显示默认的界面截图。退出后再点击的过程中,图片画好了,url已生成也设置进去了,正常显示。
为了解决这个问题,可以添加一个page全局变量记录画图状态,已画完才显示button,否则不显示。
新绘制的图片中可以将多张图片合成在一起吗?
能,在用户授权后,还可以添加用户头像和昵称信息
唯品会:有信息,点击分享button,加载约1秒,弹出Component组件。在组建内集和好物圈,微信好友,朋友圈三种分享方式。分别可点击,有不同效果。
猜想:虽然不知道源码,但share-button基本和其他页面元素一同加载出来。点击button 后有明显的1秒左右加载过程。笔者猜想canvas画图便设置在了这段时间内。注意这本质上也是先画图,再分享的过程。但在体验上完美地解决了问题2的整套动作。
网易考拉:无信息,只有一个网络图没处理
蘑菇街:有信息,在微信分享弹框内会有“。。。”等待加载。
猜想:有时主图加载时显示为视频,此时若点击过快会出现只有一张图的情况。笔者猜想是由后端生成的图片,直接返回url。点击过快可能信息还未返回,因此显示默认图片。
京东,拼多多,每日优鲜:有信息,点击过快只有主图
猜想:前端画图,未处理分享按钮,因此若点击过快没画完,则设置为主图。
苏宁易购:类似唯品会的“二级跳”,但是点击一级分享按钮后,过一会才会生成分享微信好友的按钮。这段时间内,大概率在进行canvas画图。画完图之后显示分享按钮。
保险的做法,不受微信能力的限制。在后端画图,大体上需要提供两个API。
存在的问题:后端画图无可厚非,不过在实际过程中,以Java为例,画图时间较长。如果加上来回前后端通信的时间,似乎时延是不可忍受的量级。同时由于该需求中需要显示的信息存在过期问题,缓存机制也将需要进一步考虑。
微信开放文档 ↩︎ ↩︎