众所周知,小程序开发是有诸多限制的,所以必然少不了会遇到很多坑,下面就说一说我们在开发时候遇到的一些问题,并给与解决方法与建议。
估计是每个页面的数据在小程序内部都有缓存,所以做了 10 层的限制。带来的问题就是假如页面存在循环跳转,即 A 页面可以跳到 B 页面,B 页面也可以跳到 A 页面,然后用户从 A 进入了 B,想返回 A 的时候,往往是直接在 B 页面里点击跳转到 A,而不是点返回到 A,如此一来,10 层很快就突破了。
所以我们自己对 navigateTo 函数做了一层封装,防止溢出。
// 处理微信跳转超过10层
const PAGE_LEVEL_LIMIT = 10 // 小程序页面栈上限为 10 层
function jumpUrl (url, options = {} ) {
const pages = Taro.getCurrentPages()
let method = options.method || 'navigateTo'
if (url && typeof url === 'string') {
if (method === 'navigateTo' && pages.length >= PAGE_LEVEL_LIMIT - 3) {
method = 'redirectTo'
}
if (method === 'navigateToByForce') {
method = 'navigateTo'
}
if (method === 'navigateTo' && pages.length == PAGE_LEVEL_LIMIT) {
method = 'redirectTo'
}
Taro[method]({
url
})
}
}可以看到,代码很简单,先是判断当前页面的栈数,超过了限定值后,就改为使用 redirectTo 方法,防止页面栈溢出导致错误。
上面说到,页面内容有缓存。所以假如某个页面是根据不同的数据渲染视图,新渲染时会有上一次渲染的缓存,导致页面看起来有个闪烁的变化,用户体验非常不好。其实解决的办法也很简单,每次在 onHide 生命周期中清理一下当前页面的数据就好了。
怎样理解这句话?常见的有两种情况:
这会导致什么情况呢?例如购物车页面是在底部的 TabBar 里的,假如笔者在别的页面将某个商品加入购物车,点回来的时候并不会刷新,这就和需求很不符合、体验也不友好。解决的办法很简单,每次都在页面的 onShow 生命周期里触发拉数据的逻辑,而不是在 onLoad、onReady 等生命周期去做这个事情。
小程序说到底不是 H5,不会说每次进入页面就会刷新,也不会离开就销毁,刷新、清理数据的动作都需要自己在生命周期函数里主动触发。
页面的滚动事件只能通过 onPageScroll 来监听,所以当笔者想在组件里进行监听操作时,要将该部分的逻辑提前到 onPageScroll 函数,提高了抽象成本。例如笔者需要开发一个滚动到某个位置就吸顶的 tab,本来可以在 tab 内部处理的逻辑就被提前了,减少了其可复用性。这个是小程序本身的设计缺陷,似乎没有什么很好的解决办法。
小程序与 WebView 之间不支持通过本地存储、接口之类的方式随意通信,只有 bindmessage 属性允许两者在特定情况下获取到 H5 传过来的信息。或者你也可以选择在 URL 里携带信息。
之前遇到的一个情况就是 H5 里的某个请求需要携带上登录后的 token 信息,而这个登录逻辑是在小程序里的,因而 token 储存在了小程序的 storage 里,无法在 H5 里获取。经过了一番挣扎后,最终还是通过 URL 把 token 信息带到了 H5,实现了在 WebView 里的登录态传递。
decodeURIComponent 在访问时不仅能获取小程序所携带的参数,也可以获取分享页面携带的参数。官方文档的例子:
// 这是首页的 js
Page({
onLoad: function(options) {
// options 中的 scene 需要使用 decodeURIComponent 才能获取到生成二维码时传入的 scene
var scene = decodeURIComponent(options.scene)
}
})之前写某个页面的时候,忘记了 decodeURIComponent,导致投放广告时,没有获得正确的参数。最后排查的结果是没有对参数做 decodeURIComponent 解码,又重新发了一版后,才完美解决这个问题。
像 map、canvas、video、textarea 等是由客户端创建的原生组件,原生组件的层级是最高的,并不能通过设置 z-index 来更改元素层级。之前有个需求是使用 canvas 来绘制一些东西,绘制完后需要弹出一个浮层,然后 canvas 直接把浮层挡住了。
解决的办法是使用官方提供的 cover-view 组件来包裹浮层,但体验并不好。
有弹出层时,我们希望可以把底部页面的滚动给禁止掉,这个在 H5 可以用 position:fixed 定位加滚动指定高度实现。而在小程序中,这样做会有一个延迟,页面先是会回到顶部,然后再跳到指定的地方,观感非常差。而如果是直接用 catchtouchmove='preventTouchMove' 来阻止滑动事件冒泡,那会导致弹出层里面的滚动效果给禁掉,也是行不通的。
最后的办法是在最外层使用 scroll-view 组件包裹,然后有弹出层时,将 scroll-y 属性设置为 false 从而禁止页面滚动。
Taro 在我们部门的几个核心开发者的努力下,经过多个版本的迭代,已经开发出 ESLint 插件,及补充完整了 Taro 文档。大家只要遵循 ESLint 插件规范,查看文档,不会有太大问题,有问题欢迎提 Issue。