页面栈 · vue-router 整页版
原生实现自己手写了一台 reconcile 栈引擎,vue-router 讲解版把讲解骨架与 App 并排展示。本页收敛成「整个视口就是一台 App」的形态:去掉讲解面板,只留一台在跑的应用,同一张路由表全部落在 vue-router 的现成原语上。
<keep-alive> 此刻保活的栈。可点行进详情、开设置模态、按左上角返回;移动端可从左缘右滑触发返回手势。图 0-1 是这台 App 的受控模拟:跑在一个取景框里,用 createMemoryHistory 而非 hash 或 history 模式驱动,路由状态留在内存里、不写进浏览器地址栏,因此不会与本页自身的 URL 冲突。
1 · 四条原语的分工
和原生版同一张表,只是规则挂到了 meta 上:路由本身不再知道自己是模态还是 push,由 meta.layer 告诉 <transition> 该怎么滑、告诉栈面板该怎么标。
| 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> 若不加 :include,走过的页会全部留在缓存里,与「pop 即销毁」相悖。用 :include 白名单精确控制谁被保活即可:每次导航重算当前栈,名单只留栈内的页,返回时离开的那层被移出名单、缓存随之剪除。「返回时上一页还在、而更深的那些页被销毁」就是这样实现的。
建议 · 框架接管的是 history 同步、<a> 拦截、缓存与复用(keep-alive)、过渡编排(transition)。仍要自己补的是「哪些该保活」的栈策略(include
白名单)、滑动方向判定(进或退)、以及直达时的背景合成(守卫里重建历史)。框架给的是积木,UINavigationController 式的页面栈语义仍要用积木拼出来。
2 · 直达深层页时的历史重建
直接用 URL 冷启动到 /settings/account/security 时,底下本没有商城首页这层背景。引擎在守卫里重建整条历史:先 replace 到合成的背景链,再逐级 push 到目标,这样每一次返回都逐级有处可去。图 0-1 的冷启动按钮用 createMemoryHistory 从零重放这条栈。
同一套 scheme 的从零实现见原生版,逐块拆解见 vue-router 讲解版。keep-alive 的「外层复用、只换最内一格」与本页的「公共前缀保活」是同一直觉的两种体现,嵌套路由从另一个角度讲它。