
Notes / 前端与移动端
Ionic 缓存页面里,URL 变化、页面显示和数据刷新为什么是三件事
从嵌套 Router Outlet、页面缓存和返回来源出发,复盘跨模块预览与列表刷新策略的边界。
URL 已经变化,目标页面却没有出现
个人页中的生成相册需要打开图片或视频预览。点击事件能够触发,地址栏也已经进入目标路径,但画面仍然停留在原页面。
如果只看 URL,这很像路由没有渲染成功;如果只看点击事件,又容易继续检查遮挡、事件冒泡和媒体数据。
继续梳理页面结构后,真正的问题是:个人页和生成模块位于不同的 Ionic Router Outlet 中。目标预览原本只注册在生成模块的嵌套路由下,从个人页跨模块跳转时,地址可以变化,当前可见 Outlet 却没有对应页面可以呈现。
这说明在 Ionic 应用里,需要把三件事分开:
- 路由地址是否已经变化;
- 哪个 Router Outlet 拥有目标页面;
- 当前可见页面是否真的完成了进入。
Router Outlet 不只是一个普通占位容器
普通 Vue Router 项目里,我容易把嵌套路由理解成 URL 和组件层级。Ionic Router Outlet 还承担了页面栈、转场和缓存职责。
一个页面属于哪个 Outlet,会影响:
- 它能否从当前模块被显示;
- 返回时恢复哪一个页面栈;
- 页面离开后是否仍保留实例;
- 哪些 Ionic 生命周期会再次触发。
因此跨模块预览不能只复用某个模块内部的子路由。最终做法是为个人页相册增加一个双方都能访问的根级预览入口;生成模块内部仍保留原来的嵌套路由,不为了修复跨模块入口破坏已有导航。
预览组件根据来源决定显示内容,但路由归属由进入路径决定。这样既能从个人页正常显示,也能让生成模块继续沿用自己的页面栈。
页面返回不等于组件重新挂载
预览能够打开后,另一个问题随之出现:返回个人页时,相册有时重新请求第一页,导致列表闪动、滚动位置变化和媒体重新加载。
Ionic 会缓存页面,离开页面不代表组件销毁。返回时 onMounted 往往不会再次执行,但 Ionic 的页面进入生命周期会重新触发。
这意味着数据刷新不能只依赖 Vue 挂载,也不能简单地在每次页面进入时全部重拉。因为“重新进入”可能代表不同用户意图:
- 从生成页面回来,用户希望看到刚产生的新内容;
- 从预览页返回,用户希望继续停在原来的列表位置;
- 切换账号后返回,必须重新加载新的用户数据;
- 在其他页面完成删除、收藏或喜欢操作后,只需要更新受影响的列表。
同一个生命周期入口,需要根据返回来源选择不同策略。
用一次性来源标记保护连续浏览
从相册进入预览时,我记录一个一次性的来源标记。预览返回个人页后,只跳过这一次相册首屏刷新,并立即消费标记。
流程可以写成:
相册进入预览
-> 记录单次预览返回标记
-> 打开根级预览
-> 返回个人页
-> 页面进入生命周期触发
-> 消费标记并保留当前相册
其他方式进入个人页时,仍然按正常规则刷新用户资料、背景和相册。
一次性标记的关键是范围要窄。它只表达“这一次返回需要保留浏览现场”,不能演变成关闭个人页全部刷新能力的长期开关。
全局刷新广播为什么会制造无关请求
个人页同时包含多个懒加载列表。收藏或喜欢状态变化后,如果调用“刷新所有列表”的全局函数,已经挂载的列表可能一起请求;抓包时还会看到与当前操作无关的数据类型,很难确认真正的刷新目标。
更麻烦的是,当前列表刚完成本地移除,服务端短时间内仍可能返回旧数据。立即全量回拉会把刚移除的卡片重新插回,用户看起来像需要操作两次。
最终我把刷新意图收窄到目标实例:
- 收藏变化只刷新收藏列表;
- 喜欢变化只刷新喜欢列表;
- 未打开的懒加载 Tab 不提前请求,首次进入时自然加载最新数据;
- 角色创建或删除等真正影响多处的事件,才继续使用全局刷新。
组件通过一个受控的公开方法提供重新加载能力,父级只调用当前业务需要的实例。这样调用代码本身就表达了“哪份数据发生了变化”。
乐观移除还要防止迟到响应
相册删除又增加了一层异步边界:删除成功后,当前页面可以立即移除媒体,但之前已经发出的分页请求可能稍后返回,把旧记录重新合并进列表。
因此跨页面同步不能只发一个“删除成功”事件,还需要在当前用户作用域下记录已经删除的稳定业务标识。分页响应到达时再次过滤这些记录,避免迟到数据复活。
这里的稳定标识必须来自真实任务身份,不能使用 CDN 地址等展示字段代替。展示地址可能变化或重复,业务删除需要服务端认可的唯一标识。
这套处理同时覆盖两个页面:一个页面完成删除,另一个已缓存页面收到通知后也移除相同记录;后续分页合并继续尊重本地删除状态。
当前验证边界
自动化回归还要先确认脚本是否真的执行到了目标动作。后台动画调度和脚本自身异常都可能制造“没有跳转”的假象,因此无头浏览器结果只作为线索,最终仍需在真实浏览器或模拟器中复现。
这组调整已经确认:
- 个人页图片能够进入根级预览并正常返回;
- 跨模块路由不再只改变 URL;
- 从预览返回时可以保留已有相册数据;
- 列表刷新能够按目标实例收窄;
- 构建与静态检查通过。
当时仍未完整覆盖所有视频预览、Android WebView 和不同安全区场景,因此不能把“路由结构正确”写成“双端全部通过”。
这次留下的页面模型
以后处理 Ionic 缓存页面,我会把问题拆成四层:
URL 表达的目标
-> Router Outlet 拥有的页面栈
-> 当前可见页面的 Ionic 生命周期
-> 这次进入真正需要刷新的数据
URL、页面显示和数据刷新彼此相关,却不是同一件事。只有把它们分别建模,跨模块导航和返回后的连续体验才能同时稳定。
Recommended