HarmonyOS 7 ArkUI 实战 06|Tabs 别重复加载
页签切换、缓存与懒加载很多页面第一版都不难。照着设计稿写几个Row、Column再把按钮事件接上模拟器里一跑看起来已经差不多了。真正麻烦的是第二轮需求这里加筛选那里加 loading再补一个空状态产品又说横向空间不够。页面很快就从“能跑”变成“不敢动”。这一篇我们就处理一个很具体的问题页签切换、缓存与懒加载。不堆 API也不为了显得高级去造框架。先把问题拆开再写一个能运行的最小版本最后补上真实项目里最容易漏掉的边界。1. 先别急着写代码看看问题到底在哪ArkUI 是声明式 UI。这个词听着有点抽象其实可以理解成一句话页面应该描述“当前状态下长什么样”而不是到处写命令去手工改界面。很多页面后期难维护不是因为 ArkTS 难而是三个东西混在了一起页面结构、业务状态、交互流程。一个点击事件里既改变量又发请求又拼参数还顺手控制弹窗短期很快后面排错就很痛苦。我写业务页时通常先画三个框页面有什么区域哪些数据会变化变化由谁触发。十分钟想清楚往往比直接敲一小时代码更省时间。2. 先做最小可运行版本下面这段代码只保留本篇最核心的结构State currentIndex: number 0 State loaded: boolean[] [true, false, false] Tabs({ index: this.currentIndex }) { TabContent() { TodoPage() }.tabBar(待办) TabContent() { DonePage() }.tabBar(已完成) TabContent() { MinePage() }.tabBar(我的) } .onChange((index: number) { this.currentIndex index this.loaded[index] true })这里不要急着抽象。先在 DevEco Studio 里跑起来看模拟器上的行为是否符合预期。教程里最容易出现的问题就是代码看着“架构很好”结果复制进工程缺一堆上下文。我们反过来先保证核心链路成立。3. 为什么这样写会更稳关键不是少写几行而是职责清楚。页面知道自己当前是什么状态组件知道自己负责显示什么事件只负责触发变化。例如用户点一次按钮如果背后有异步请求页面至少要知道“正在请求”。否则连续点三次就可能真的发三次请求。再比如列表刷新时如果刷新和加载更多共用一个模糊的loading很容易出现底部正在加载时整个页面突然被遮住。状态命名也别太随意。flag1、isShow2这种变量写的时候快两周后自己都不知道是什么意思。宁愿长一点也写成refreshing、showFilterPanel、pageStatus。4. 把正常路径和异常路径一起写只写成功流程是 Demo把失败、空数据和恢复流程补齐才接近项目。异步方法我一般会保留完整的try / catch / finally。try负责正常请求catch决定失败后页面怎么表现finally则非常适合恢复 loading。这样即使请求抛异常也不至于让按钮永远停在“处理中”。async loadData() { if (this.loading) return this.loading true try { const data await this.requestData() this.items data } catch (err) { console.error([TabsPage] loadData failed) } finally { this.loading false } }注意第一行的防重复判断。它看起来不起眼但在真实业务里特别有用。5. UI 状态不要越堆越多另一个常见问题是 boolean 越写越多State loading: boolean false State empty: boolean false State error: boolean false State success: boolean false这四个变量理论上能组合出很多状态但业务真正允许的通常只有几个。万一loading和error同时变成true到底显示谁互斥状态更适合收口成枚举enum PageStatus { Idle, Loading, Success, Empty, Error } State pageStatus: PageStatus PageStatus.Idle这样页面在某一时刻只处于一个明确状态阅读和排错都会轻松很多。6. 组件到底什么时候拆不是代码超过 100 行就必须拆。更实用的判断有三个这个区域有没有独立职责有没有自己的局部状态以后会不会复用满足其中一个就值得考虑拆组件。反过来一个只有两行文字、没有状态、也不会复用的区域硬拆成单独文件反而增加阅读成本。我更习惯把页面看成“组织者”。页面负责把标题区、筛选区、内容区组合起来真正的细节交给业务组件。网络请求、数据转换、持久化则尽量不要全部塞在页面文件里。7. DevEco Studio 里怎么排查“页面不对”遇到 UI 没变化先别怀疑框架。按这个顺序查第一步看点击事件有没有触发。第二步看状态值是不是真的改了。第三步看当前 UI 是否依赖这个状态。第四步如果有异步逻辑看异常是不是提前打断了后面的代码。日志建议带上页面名console.info([TabsPage] start) console.info([TabsPage] status changed)别一次打印一个巨大对象。真正出问题时日志越多不一定越容易看。8. 再往真实业务靠一步页签切换、缓存与懒加载放到真实项目里通常还会碰到页面重新进入、窗口尺寸变化、接口慢、用户连续操作、数据为空等情况。所以写完“正常效果”以后我会故意做几次破坏性测试断网再点一次连续点五次让接口返回空数组切到别的页面再回来把文案改得特别长。很多布局和状态问题这时候才会暴露。9. 不要为了工程化而工程化项目里还有一种反方向的问题刚写两个页面就开始设计万能基类、万能弹窗、万能列表。抽象应该来自重复而不是来自想象。业务还没稳定时先写清楚通常比先写通用更重要。等两三个页面真的出现相同结构再抽公共组件边界会准确很多。资源也是一样。会重复出现的颜色、尺寸、文案可以逐步收口只出现一次的东西没必要第一天就建立十层配置。10. 提交前做一次快速自检我一般会检查这些事情首次进入是否正常连续点击是否重复请求loading 能不能恢复空数据有没有页面失败后能不能重试长文本会不会顶坏布局列表数据多起来以后是否明显卡顿页面重新进入后状态是不是预期值。这些检查没有炫技成分却非常接近线上真正会出现的问题。最后总结这一篇真正要练的不是记 API而是形成一个稳定顺序先拆页面结构再确定状态归属然后写交互最后补异常路径。HarmonyOS 7 的 ArkUI 本身并不难页面越写越乱通常是因为结构和状态没有先想清楚。把这个顺序养成习惯后面无论写列表、表单、Tabs 还是复杂业务页都会顺很多。