① 用 <component :is="名字" /> 在三个组件之间切换,而不是写一串 v-if;
② 切走的时候到底是「卸载」还是「进缓存」,由 <KeepAlive> 说了算;
③ 慢组件交给 defineAsyncComponent,加载态和超时态都有专门的组件来显示;
④ 子组件默认对父级封闭,想让它的方法能被 ref 调用,必须点名暴露出去。
一句话记住::is 用组件名,切换只改一个字符串,配合 KeepAlive 才谈得上「缓存了哪个」;
KeepAlive 只认 name,include / exclude 拿 name: 'tab-a' 去比对,而且缓存 ≠ 暂停,副作用要在 onActivated / onDeactivated 里自己管;
异步组件四个态:delay 内静默 → loading → 成功内容 / 超时 errorComponent,重试得换一个新对象;
ref 不是后门,父级只能调到子组件点名暴露出来的方法。
| 东西 | 怎么写 | 注意点 |
|---|---|---|
include / exclude | <KeepAlive include="tab-a">,也可以传数组或正则 | 按组件的 name 匹配,不是按标签名;这里每个 tab 都显式写了 name: 'tab-a'。两个都不写 = 全缓存 |
max | <KeepAlive :max="10"> | 缓存上限,超了按最近最少使用踢掉一个,别拿它当内存泄漏的解药 |
onActivated / onDeactivated | 只在 KeepAlive 里触发 | 不包 KeepAlive 时走的是 onMounted / onUnmounted;缓存期间 setInterval 这类副作用并没有停,要在 onDeactivated 里自己停 |
defineAsyncComponent | { loader, loadingComponent, errorComponent, delay, timeout } | loader 返回 Promise;delay(默认 200ms)之内不闪 loading;timeout 不写就永不超时;同一个异步组件对象会缓存结果,重试要重建它或用 onError;交给 :is 之前存进 shallowRef 而不是 ref |
defineExpose / expose | <script setup> 里 defineExpose({ publicMethod });Options 写 expose: ['publicMethod'] | <script setup> 的组件默认封闭,父级 ref 只能拿到你点名暴露的成员;Options API 不写 expose 则整个实例敞开 |