复盘——微信小程序自定义tabbar结构设计优化导致的问题

203 阅读7分钟

要拿捏局部优化和系统优化

文章简单记录下,小程序自定义tabbar结构设计优化,导致的多页面代码变更的问题,和解决思维的变化

背景

全局layout组件有个error-page样式会覆盖住自定义tabbar,需要解决

image.png

自定义tabbar组件目前是在各个页面引用的,而不是统一在公共的layout组件使用,这个属于历史原因了,所以就有这个问题了

这里有个小点:微信小程序的app.jsontabbar可支持放入5个以上的页面,这些页面将会拥有switchTab的切换效果,但底部tabbar只能展示5个

原先代码case

<!-- index页面 --!>
<layout>
    <view>
        <!-- content --!>
    </view>
    <tabbar />
    <view style="height:50px"></view>
</layout>

<!-- layout组件代码 --!>
<view>
    <view class="content-page">
        <slot />
    </view>
    <view class="error-page" wx:if="{{ showErrorPage }}">
        接口报错啦
    </view>
</view>

<style>
    .content-page {
        z-index: 1;
        position:relative;
    }
    .error-page {
        z-index: 2;
        position: fixed;
        height: 100vh;
        background-color: #fff;
    }
</style>

其实主要本质上是因为tabbar位置放错了,应该得把tabbar组件放到layout组件,而不是放到页面里,这样就能和error-page保持同级,从而不会被盖住,如下:

<!-- layout组件代码 --!>
<view>
    <view class="content-page">
        <slot />
    </view>
    <view class="error-page" wx:if="{{ showErrorPage }}">
        接口报错啦
    </view>
    <tabbar />
    <view style="height:50px"></view>
</view>

为什么要说他呢,因为一开始我其实不敢把这个自定义tabbar放在layout里,我的想法是能简单就简单,能少改动就少改动,能不影响之前的就不影响之前的

也就是一开始想“局部修补”,但发现在复杂结构中,局部修补只会带来更多局部修补。

所以一开始我的解决的切入点就是error-pagecontent-page这俩部分,比方说

  • error-page判断有没有自定义tabbar,动态变更高度:calc(100vh - 50px)50px自定义tabbar高度,因为error-pagefixed+100vh,所以他就盖住了自定义tabbar

    • 这里有个点,虽然自定义tabbar层级可能很高,但error-page最终的层级比较还是content-page
  • 考虑到content-page设置了z-index,所以可以把content-pagez-index``设置为unset,这样error-page就能和自定义tabbar进行比较了,从而自定义tabbar不会被盖住

以上2点,就是我一开始解决时想到的点

这里说明下三个方案的优缺点,加上抽取自定义tabbar放到layout的方案

方案改动成本可维护性健壮性长期收益
❌ 高度调整 error-page✅ 低❌ 差❌ 差❌ 差
❌ unset z-index content-page✅ 低⚠️ 一般⚠️ 一般❌ 差
✅ 移动 tabbar 到 layout❌ 高✅ 好✅ 好✅ 高

这里的主要问题就是:对原结构进行妥协,没有要做到系统性优化

只是把当前问题解决了,他带来的隐藏问题还需要一个一个页面进行查看,那这就和重新优化tabbar引入位置带来的问题一样,也需要一个个页面查看,既然投入的成本类似,那为什么不尝试用更好的办法呢,优化系统结构

不过呢,局部优化和整体优化有时候是有一定的取舍的,也就是不是完全反对局部优化,需要看情况,总结就是

  • 结构有误、问题普遍、未来可期 ⇒ 优化结构
    • 影响到了全部页面,每个页面都可能有类似问题等,后期也有类似问题等
  • 局部异常、代价可控、生命周期短 ⇒ 优化局部
    • 比方说,只有一个页面有问题,或者需要紧急上线

问题&设计

以上是背景,接下来就是一些问题&设计

iphone安全距离

项目constant()env()
状态已废弃✅ 推荐
兼容性老版 iOS Safari(12 及以前)iOS 11.2+,现代浏览器支持
用法constant(safe-area-inset-bottom)env(safe-area-inset-bottom)

其他可用安全距离

变量名含义
safe-area-inset-top顶部安全距离(刘海/状态栏)
safe-area-inset-bottom底部安全距离(Home Indicator)
safe-area-inset-left左边安全距离(圆角屏)
safe-area-inset-right右边安全距离(圆角屏)
padding-bottom: constant(safe-area-inset-bottom);
padding-bottom: env(safe-area-inset-bottom);

bottom: constant(safe-area-inset-bottom);
bottom: env(safe-area-inset-bottom);

自定义tabbar引发的一系列高度问题

原先页面中都有一段这样的代码,height: 50px起一个占位作用,因为tabbarfixed布局

<tabbar />
<view style="height:50px"></view>

现在放到了layout组件里

<!-- layout组件代码 --!>
<view>
    <view class="content-page">
        <slot />
    </view>
    <view class="error-page" wx:if="{{ showErrorPage }}">
        接口报错啦
    </view>
    <tabbar />
    <view style="height:50px"></view>
</view>

为什么要说这个呢,因为页面里有些样式会这么写

.my-content-page {
    height: 100vh
}

此时把自定义tabbar组件移到layout组件里,和content-page保持同级,就会导致height: 100vh多了50px,会影响滚动或者其他的样式,所以原来的页面需要减掉50px

layout怎么判断是否展示自定义tabbar

这里推荐使用每个页面传递参数的方法进行标识

<layout is-tab-bar-page="{{ true }}"></layout>

这样layout可以更快的判别是否渲染自定义tabbar,核心原因是微信小程序的组件的生命周期原因

微信小程序的组件的生命周期:created -> attached -> ready

简单理解可以看成vue的生命周期,比如 beforeCreate -> created -> mounted

我在created环节就能拿到props数据了,从而更快的判别是否渲染自定义tabbar

还有个方法可以判别:

可以在mounted(ready)环节,获取页面实例,获取页面名、页面路径,判断是否在tabbar,从而判别是否渲染自定义tabbar

但他是在mounted环节判断的,速度要比beforeCreate(created)慢,所以推荐向子组件传参

我这里的欠缺点,没有考虑到生命周期的影响,我一开始采用的是后者,进行代码review后使用了前者,所以记录下

按钮点击没有反应

这算是个历史bug,刚好讲讲,个人的解决思路,顺便记录下,代码case

api.submit().then(res => { wx.navigate({ url: 'pages/index/index' }) })

手机上看到时,发现点击没反应,没有报错提示,也没有跳转,那么至少可以简单的分析出来,接口可能发生了点问题,从而没有走进跳转逻辑

至于报错提示没有,需要了解处理请求返回结果的逻辑怎么做报错提示的

我这里的代码是只对个别错误码进行了toast提示,个别没有,那接下来该怎么办,复现又不好复现

此时需要让后端人员,查一下接口日志,看看有没有发起请求、请求报错等

我这里得到的结果就是————没有登录。

考虑到,我页面初始化就会判断是否登录,没有登录就会发起登录,所以这里需要分析下,为什么会没有登录,token问题还是什么问题,这就需要让后端人员看了

我这里的欠缺点:KiBanba不熟悉、对没有登录不敏感(因为页面初始化就会发起登录,所以就得确认,是不是token过期了,或者后端逻辑问题等)

面对问题的解决思路

刚好在整理一下问题的解决思路

广泛来说:个人解决 -> AI解决 -> google、社区、issue解决

问题现象有很多:接口报错、没反应、页面加载速度慢、控制台报错、页面异常等

这里主要说明个人解决思路,以我的error-page覆盖问题来说明

  1. 问题是什么,描述问题现象
  2. 寻找触发问题的代码,可以通过接口、控制台、现象展示分析
  3. 判断这是前端问题还是后端问题
  4. 分析造成问题的核心原因,局部方面,系统方面,要带着全局观来看,可以查日志,复现问题环节,调试等等
  5. 提出、评估解决问题的手段,有时候还需要大胆猜测,小心求证
  6. 实践

如果是诡异的问题,可以多多比较,二分法等,比较可以比机型、环境、参数、版本等

如果有解决不了的问题,需要带着代码执行流程的进行模拟一遍,然后分析

考虑到代码中会有一些常用的封装逻辑,比如公共layout、公共请求、main.js等,这些也是需要注意的,总之而言,带着代码执行流程去分析,比方说一个接口发起的代码执行流程:按钮触发事件 -> 公共请求 -> 回调

总结

多多复盘,查漏补缺,沉着冷静,带着代码流程去分析,保持怀疑