页面栈 · vue-router 整页 App 对照
页面栈的原生实现是「自己手写一台 reconcile 栈引擎」,vue-router 讲解版则把讲解骨架和 App 并排展示。这一页收敛成整个视口就是一个 App 的形态——去掉讲解面板,只留一台在跑的应用:同一张路由表、同一套「稳定入口 ↔ 可变目标」模型,全部落在 vue-router 的现成原语上。
下面的 lab 是这台 App 的受控模拟:它跑在一个 phone 取景框里,用 createMemoryHistory 而非 hash / history 模式驱动——路由状态留在内存里、不写进浏览器地址栏,因此不会与本页自身的 URL 冲突。取景框右侧同步画出
<keep-alive> 此刻保活的栈。点行进详情、开设置模态、按左上角返回;移动端可从左缘右滑触发返回手势。
1 · 一张路由表,四条原语各管一段
和原生版同一张表,规则挂到了 meta 上——路由本身不再「知道」自己是模态还是 push,由 meta.layer 告诉 <transition> 该怎么滑、告诉栈面板该怎么标。整套页面栈语义拆给四条 vue-router 原语:
| vue-router 原语 | 在这台 App 里负责 |
|---|---|
meta.layer (base / modal) |
区分横向 push 与从底部浮起的模态,决定进 / 退的滑动方向 |
<transition :enter-from-class :leave-to-class> |
按导航是进还是退,给前后两层不同的进出场 class (off-x / off-y / under) |
<keep-alive :include> |
白名单 = 「当前还活着的栈」:push 时上一层留在名单内保活、pop 时移出名单即缓存剪除、组件销毁 |
beforeEach 守卫 |
直达深层设置页时,把来源页记下来供合成背景,让逐级返回都有处可去 |
<keep-alive> 默认会把所有走过的页都缓存住,与「pop 即销毁」相悖。解法是用 :include 白名单精确控制谁被保活:每次导航重算当前栈,名单只留栈内的页;返回时离开的那层被移出名单,缓存随之剪除。这正是「返回时上一页还在、而更深的页已销毁」的实现。
框架替你接管了: history 同步、<a> 拦截、缓存与复用 (keep-alive)、过渡编排 (transition)。仍要自己补的是:「哪些该保活」的栈策略(include 白名单)、滑动方向判定(进 /
退)、以及直达合成背景(守卫里重建历史)。框架给的是积木,UINavigationController 式的页面栈语义仍要你用积木拼出来。
2 · 直达深层页:栈底本没有背景
直接用 URL 冷启动到 /settings/account/security 时,底下本没有「商城首页」这层背景。引擎在守卫里重建整条历史——先 replace 到合成的背景链,再逐级 push 到目标,这样每一次返回都逐级有处可去。lab 里的「直达 / 冷启动」按钮模拟这一过程(createMemoryHistory
从零重放这条栈)。
3 · 相关页
- 本系列 · 页面栈的原生 JS 实现——同一套 scheme 不依赖任何框架,只用 History API + 一个声明式 reconcile,把「保活 / 销毁 / 合成背景」从零搭出来。
- 本系列 · vue-router 讲解版——把路由表、
keep-alive白名单、过渡方向逐块拆开讲解,与本页是同一实现的两种呈现。 - 本系列 · 嵌套路由 / layout——
keep-alive的「外层复用、只换最内一格」与这里的「公共前缀保活」是同一直觉的两种体现。 - Vue Router · Transitions——
router-viewv-slot +transition+keep-alive的官方组合写法,本页的方向滑动就建立在它之上。