去年年底,微信小程序的分包大小已经到达了 12M 大小,一方面说明小程序的确逐步为开发者放开更大的权限,另外一方面也说明了对于某些小程序 8M 的大小已经不够用了。我我的今年也是在开发一个 to B 小程序应用。这里列举一些跨页面交互的场景。html
对于 B 端应用的业务需求来讲,小程序开发的复杂度相对比网页开发要复杂一些。一个是双线程的处理机制问题,另外一个是页面栈之间交互问题。前端
注: 笔者目前只须要开发微信小程序,为了在小程序页面中可使用 properties behaviors observers 等新功能,已经使用 Component 构造器来构造页面。具体能够参考微信小程序 Component 构造器。若是你也没有多端开发的需求,建议尝试使用,能够获得不错的体验。react
对于小程序在页面中点击触发 wx.navigateTo 跳转其余页面,中间会有一段时间的空白加载期(对于分包出去的页面,空白期则会更长),可是这是小程序内部机制,没有办法进行优化。咱们只能眼睁睁的等待这段没有意思的空白期过去。git
当考虑到跳转页面后的第一件事情即是取数逻辑,那么咱们是否可以进行优化呢?答案是确定的。咱们没有办法直接在当前页面取得数据以后再进行跳转操做(这样操做更很差),可是咱们却能够利用缓存当前的请求,详情能够参考我以前的博客文章 ——Promise对象 3 种妙用。github
代码以下:小程序
const promiseCache = new Map() export function setCachePromise(key, promise) { promiseCache.set(key, promise) } export function getCachePromise(key) { // 根据key获取当前的数据 const promise = promiseCache.get(key) // 用完删除,目前只作中转用途,也能够添加其余用途 promiseCache.delete(key) return promise }
作一份全局的 Map,而后利用 Map 缓存 promise 对象,在跳转以前代码为:微信小程序
// 导入 setCachePromise 函数 Component({ methods: { getBookData(id) { const promise = // promise 请求 setCachePromise(`xxx:${id}`, promise) }, handleBookDetailShow(e) { const id = e.detail this.getBookData(id) wx.navigateTo({url: `xx/xx/x?id=${id}`}) } } })
而跳转以后的代码也以下所示:api
// 导入 getCachePromise 函数 Component({ properties: { id: Number }, lifetimes: { attached () { const id = this.data.id // 取得全局缓存的promise const bookPromise = getCachePromise(`xxx:${id}`) bookPromise.then((res) => { // 业务处理 }).catch(error => { // 错误处理 }) } }, methods: { getBook() { // 获取数据,以便于 错误处理 上拉刷新 等操做 } } })
如此即可以同时处理取数和页面加载的逻辑,固然,这个对于页面有耦合性,不利于后续的删除与修改。但考虑若是仅仅加在分包跳转之间可能会有不错的效果。promise
想要无侵入式,能够进一步学习研究 微信小程序之提升应用速度小技巧 以及 wxpage 框架,同时考虑到不管是 ToC 仍是 ToC 用户,都有可能存在硬件以及网络环境等问题,该优化仍是很是值得的。缓存
固然微信小程序为了减小冷启动时间,提供了周期性更新 数据预拉取 功能。
注: 上面的 promiseCache 只做为中转的用途,不做为缓存的用途,若是你考虑添加缓存,能够参考我以前的博客文章—— 前端 api 请求缓存方案。
若是是 pc 端中进行交互,对于数据的 CRUD。例如在详情页面进行了数据的修改和删除,返回列表时候就直接调取以前存储的列表查询条件再次查询便可,而对于移动端这种下拉滚动的设计,就没有办法直接调用以前的查询条件来进行搜索。
若是从列表页面进入详情页面后,在详情页面只会进行添加或者修改操做。而后返回列表页面。此时能够提示用户数据已经进行了修改,请用户自行决定是否进行刷新操做。
如在编辑页面修改了数据:
const app = getApp() component({ methods: { async handleSave() { //... app.globalData.xxxChanged = true //... } } })
列表界面:
const app = getApp() component({ pageLifetimes: { show() { this.confirmThenRefresh() } }, methods: { confirmThenRefresh() { // 检查 globalData,若是当前没有进行修改,直接返回 if(!app.globalData.xxxChanged) return wx.showModal({ // ... complete: () => { // 不管确认刷新与否,都把数据置为 false app.globalData.xxxChanged = false } }) } } })
固然了,咱们也能够利用 wx.setStorage 或者 getCurrentPage 获取前面的页面 setData 来进行数据通知,以便用户进行页面刷新。
若是仅仅只涉及到修改数据的前提下,咱们能够选择让用户进行刷新操做,可是若是针对于删除操做而言,若是用户选择不进行刷新,而后用户又不当心点击到了已经被删除的数据,就会发生错误。因此若是有删除的需求,咱们最好在返回列表页面前就进行列表的修改,以避免形成错误。
github 上有不少的 pub/sub 开源库,若是没有什么特定的需求,找到代码量最少的就是 mitt 这个库了,做者是喜欢开发微型库的 developit 大佬,著名的 preact 也是出于这位大佬之手。 这里就不作过多的介绍,很是简单。你们可能都能看明白,代码以下(除去 flow 工具的检查):
export default function mitt(all) { all = all || Object.create(null); return { on(type, handler) { (all[type] || (all[type] = [])).push(handler); }, off(type, handler) { if (all[type]) { all[type].splice(all[type].indexOf(handler) >>> 0, 1); } }, emit(type, evt) { (all[type] || []).slice().map((handler) => { handler(evt); }); (all['*'] || []).slice().map((handler) => { handler(type, evt); }); } }; }
仅仅只有3个方法,on emit以及 off。
只要在多个页面导入 生成的 mitt() 函数生成的对象便可(或者直接放入 app.globalData 中也可)。
Component({ lifetimes: { attached: function() { // 页面建立时执行 const changeData = (type, data) => { // 处理传递过来的类型与数据 } this._changed = changeData bus.on('xxxchanged', this._changed) }, detached: function() { // 页面销毁时执行 bus.off('xxxchanged', this._changed) } } })
这里mitt能够有多个页面进行绑定事件,若是需求仅仅只涉及到两个页面之间,咱们就可使用 wx.navigateTo 中的 EventChannel (页面间事件信息通道)。能够参考微信小程序wx.navigateTo方法里的events参数使用详情及场景,该方案的利好在于,传递到下一个页面的参数也能够经过 EventChannel 来通知,以便于解决 properties 传递数据不宜过大的问题。
注: 一个页面展现不少信息的时候,会形成小程序页面的卡顿以及白屏。小程序官方也有长列表组件 recycle-view。有需求的状况下能够自行研究,这个不在这里详述。
若是你以为这篇文章不错,但愿能够给与我一些鼓励,在个人 github 博客下帮忙 star 一下。
博客地址