Vue Router 与 Pinia

共 26 题
📑 题目列表 26 题
#
★★★

1. 路由懒加载与 defineAsyncComponent 的代码分割协作

路由懒加载与 defineAsyncComponent 如何协作实现代码分割?两者的分工与取舍是什么?

  • 路由级懒加载:component: () => import() 拆分路由页面 chunk
  • defineAsyncComponent 的组件级代码分割与状态配置
  • 两者叠加时的加载态与错误处理

路由懒加载是路由配置中的 component: () => import('./views/Home.vue'):构建工具把每个路由页面拆分为独立 chunk,导航到该路由时才加载对应代码,实现"按路由分包"的首屏瘦身。defineAsyncComponent 是组件级的异步包装:defineAsyncComponent(() => import('./Heavy.vue')) 把单个组件拆分为 chunk,按需加载,并支持 loadingComponent、errorComponent、delay、timeout、onError 等加载状态配置。二者协作:路由页面内的大组件用 defineAsyncComponent 二次拆分(页面 chunk + 组件 chunk 分层加载),配合 Suspense 统一展示骨架屏;加载失败时分别配置错误兜底(路由守卫/错误页、组件的 errorComponent)。取舍:路由级懒加载是默认首选(粒度合理、无需额外配置);组件级异步加载用于"页面内的大体积低频模块"(编辑器、图表、富文本)或需要精细 loading 控制的场景;注意避免过度拆分(chunk 过多导致请求碎片化),结合 prefetch/preload 策略(路由预取、hover 预加载)平衡首屏与后续体验。

本题考察代码分割的两级粒度:路由级(页面 chunk)与组件级(组件 chunk)及其协作方式。回答时说明各自机制、协作形态(Suspense + loading/error 配置)与拆分策略(避免碎片化、预加载配合),即完整。

#
★★★

2. Pinia 的 $reset、$subscribe、插件机制

Pinia 的 $reset、$subscribe 与插件机制分别解决什么问题?如何正确使用?

  • $reset 将 state 恢复为初始值(options store)
  • $subscribe 订阅 state 变化(支持 detached、flush 选项)
  • 插件机制通过 pinia.use 扩展 store 能力

$reset() 把 store 的 state 重置为定义时的初始值,适用于"退出登录清空、表单重置"等场景(注意仅 options store 原生支持,setup store 需自行实现重置函数)。$subscribe(callback, options) 订阅 state 的深度变化(patch 或直接修改均触发),options 支持 detached(组件卸载后仍继续订阅,需手动 unsubscribe)与 flush: 'sync'/'pre'/'post' 控制回调时机,常用于持久化(变更即写入 localStorage)、调试日志、统计上报;与组件内 watch(store.state) 相比,$subscribe 面向 store 生命周期、默认绑定组件作用域、对 patch 更友好。插件机制:pinia.use(plugin) 在 store 创建时注入扩展——可给所有 store 添加共享属性/方法、包装 action(拦截、埋点、错误上报)、读取 context(pinia、app、options、store),典型应用是持久化插件(pinia-plugin-persistedstate)、日志/埋点中间件、权限助手。三者组合可构建"可重置、可观测、可扩展"的状态层。

本题考察 Pinia 的三个横切能力:重置(生命周期)、订阅(观测)、插件(扩展)。回答时分别说明机制与适用场景,重点讲 $subscribe 的选项语义(detached/flush)与插件的 context 结构及典型应用,即覆盖完整。

#
★★★

3. ScrollBehavior 与滚动位置恢复

Vue Router 的 scrollBehavior 如何实现滚动位置恢复?有哪些实践要点?

  • scrollBehavior(to, from, savedPosition) 的返回值语义
  • savedPosition 在浏览器前进/后退时的恢复
  • el 与 offset 实现元素滚动(锚点、列表定位)

Vue Router 4 的 scrollBehavior(to, from, savedPosition) 在导航完成后调用,返回值决定滚动行为:返回 { top, left } 滚动到绝对位置;返回 { el, top, offset } 滚动到指定元素(锚点、列表项);返回 savedPosition 恢复浏览器前进/后退时的历史位置;返回 false/空则不动。实践要点:恢复逻辑应与页面内容渲染配合——若目标内容异步加载(数据请求后列表才出现),需在内容就绪后再执行滚动(用 nextTick 或等待数据 promise),否则滚动无效;对"列表页返回保留位置"场景,可结合 KeepAlive 缓存 DOM 或在 scrollBehavior 中按路由 meta 定制;返回 promise(async scrollBehavior)可等待异步条件满足后再滚动。注意 history 模式下 savedPosition 依赖浏览器会话历史,刷新页面后不存在,需自行持久化方案(sessionStorage 记录滚动位置)。

本题考察路由滚动控制的机制与工程细节:核心是"返回值决定滚动策略"与"滚动时机需与内容渲染同步"。回答时讲清三种返回形态、savedPosition 的前进/后退语义、异步内容的时序处理与刷新场景的持久化补充,即完整。

#
★★★

4. Pinia 的 setup store 与 options store 在大型状态管理的工程取舍

Pinia 的 setup store 与 options store 在大型状态管理中的取舍是什么?如何选择?

  • options store:state/getters/actions 的结构化声明
  • setup store:以组合式函数风格组织,返回 ref/函数
  • 类型推导、复用与测试差异

options store 以 state/getters/actions 固定结构声明,直观、易上手、$reset 原生支持,适合简单直接的状态单元;setup store 则像组合式函数一样组织:内部自由使用 ref/computed/函数/其他 store,返回一个对象(state 用 ref、派生用 computed、操作用函数),更适合复杂业务(依赖注入、逻辑复用、跨 store 协作、测试注入 mock 方便),且类型推导与编辑器体验更佳(返回类型精确推断),$reset 需自行实现。大型项目取舍:优先 setup store——复杂状态与协作逻辑的组织更自然,配合组合式 API 心智一致;简单/标准化状态可用 options store 降低样板。组织原则:按领域拆分 store(单一职责)、store 间通过 action 协作而非直接改对方 state、共享的派生与枚举用 getters、保持 state 可序列化。迁移上两者可共存,Pinia 保证 API 一致(useStore 用法相同)。

本题考察两种 store 形态的选型:options 结构化、setup 组合化。回答时对比结构、能力($reset)、类型推导、测试与协作差异,并给出大型项目的组织原则(领域拆分、协作规范、可序列化),即为核心。

#
★★★

5. Vue Router 4/5 createRouter 与 Composition API 的路由守卫嵌套工程价值

Vue Router 4/5 的 createRouter 与组合式 API 如何协作?路由守卫嵌套有什么工程价值?

  • createRouter 创建路由器实例与 useRouter/useRoute 的组合式访问
  • 全局守卫、路由独享守卫、组件内守卫的分层
  • 守卫链的执行顺序与 next/return 契约

createRouter({ history, routes }) 创建路由器实例,在组合式 API 中通过 useRouter()(编程式导航)与 useRoute()(当前路由响应式对象)访问,脱离 Options API 的 this.$router,可在任何 setup/composable 中使用。守卫分三层:全局(beforeEach/beforeResolve/afterEach)、路由独享(路由配置的 beforeEnter)、组件内(beforeRouteEnter/beforeRouteLeave/beforeRouteUpdate 或组合式 onBeforeRouteLeave/onBeforeRouteUpdate),形成分层治理:全局做认证/埋点、独享做页面级权限、组件内做数据保存与离开确认。工程价值:嵌套路由中每层守卫按"父到子"顺序执行(全局 → 父级独享 → 子级独享 → 组件内),可精确控制导航流水线(登录态校验 → 页面权限 → 数据预取 → 离开拦截);组合式 API 让守卫与组件逻辑内聚(在 composable 中注册组件内守卫),便于复用与测试。注意守卫中 next 已废弃(Vue Router 4 用 return 值/throw),以及异步守卫对导航延迟的影响。

本题考察路由守卫体系与组合式 API 的融合:回答按"实例创建与访问(useRouter/useRoute)→ 守卫分层 → 执行顺序与契约 → 组件内守卫的组合式用法"展开,突出嵌套场景的分层治理价值,即完整。

#
★★★

6. Vue Router 4 的 useRouter/useRoute 在 Composition API 的工程化应用

Vue Router 4 的 useRouter 与 useRoute 在组合式 API 中有哪些工程化应用?使用注意点是什么?

  • useRouter 获取路由实例(编程式导航、守卫注册)
  • useRoute 获取当前路由响应式对象(query/params/meta)
  • 在 composable 与组件中的复用

useRouter() 返回当前路由实例,用于编程式导航(router.push/replace)、守卫管理(beforeEach 注册)与路由信息访问;useRoute() 返回当前路由的响应式对象,包含 path、query、params、meta、name、fullPath 等,变化时自动触发依赖更新——组件内可直接在模板使用 route 或 watch(() => route.params.id) 响应参数变化。工程化应用:把路由逻辑封装为 composable(如 usePageMeta 读取 meta 配置标题/权限、useRouteParams 处理参数默认值与类型转换);列表页监听 query 变化重新请求数据;权限控制结合 meta 与守卫。注意点:useRoute 返回的对象是响应式的,解构会失去响应性(需 toRefs 或按需 watch);useRouter 必须在组件 setup 或 composable 内调用(依赖注入上下文);watch route 时注意"相同路由不同参数"的触发(用 route.query 或 watch 全对象 + immediate)。

本题考察路由组合式 API 的日常应用:useRouter 管"操作",useRoute 管"状态"。回答时说明两者的获取方式、响应式语义(解构陷阱)、以及典型组合(封装 composable、watch 参数变化、meta 驱动页面能力),即覆盖工程全貌。

#
★★★

7. router.addRoute() 动态注册路由与权限控制

router.addRoute() 如何实现动态注册路由?在权限控制中的应用与边界是什么?

  • addRoute(route) 运行时添加路由记录,支持嵌套与命名
  • 动态菜单/权限路由的按需注册
  • 移除路由(removeRoute)与路由重置

router.addRoute(route) 在运行时向路由表添加路由记录,返回移除函数;支持传入带 name 的路由与父级 name 实现嵌套挂载(addRoute('parent', child))。权限控制的经典模式:登录后根据用户权限动态生成路由表(过滤无权限页面),addRoute 逐条注册,配合全局守卫 beforeEach 校验访问;登出/切换账号时用 removeRoute 移除并按新权限重建,避免权限残留。边界与注意:动态路由注册后匹配立即生效,但需确保 404 兜底路由(catch-all :pathMatch(.))在动态路由之后匹配(添加顺序影响优先级,通常 404 最后注册);动态添加的路由要在守卫中避免重复注册(用 name 或已注册集合判断);SSR/服务端渲染中动态路由需在服务端同步注册以保证水合一致;权限校验不能只依赖前端隐藏(路由守卫),敏感资源需后端鉴权兜底。

本题考察动态路由在权限体系的落地:核心是"运行时注册 + 权限过滤 + 清理重建"。回答时给出 addRoute/removeRoute 的用法、动态路由表生成流程、404 顺序与重复注册的边界、以及前后端鉴权分工,即完整。

#
★★★

8. Vue Router 的动态路由、嵌套路由与守卫(beforeEach、beforeResolve)

Vue Router 的动态路由与嵌套路由如何工作?beforeEach 与 beforeResolve 守卫有何区别?

  • 动态路径参数(:id、:pathMatch(.))的匹配与传参
  • 嵌套路由的 children 与组件层级
  • beforeEach 与 beforeResolve 的执行时机差异

动态路由通过路径参数(:id)与 catch-all(:pathMatch(.))匹配变化 URL,参数经 route.params 获取;嵌套路由用 children 声明父子关系,子路由渲染到父组件的 中,形成"父布局 + 子页面"的层级结构,URL 与组件层级一一对应。守卫差异:beforeEach 是导航开始后的首个全局守卫(适合认证、重定向、登录态校验),beforeResolve 在所有组件内守卫与异步路由组件解析完成后、导航确认前执行(适合"确保数据已就绪再进入"的最终校验与数据预取);二者都支持 async/await 与 return false 取消导航。工程应用:beforeEach 做全局鉴权与白名单跳转,路由独享/组件内守卫做页面级控制,beforeResolve 聚合异步数据预取(配合 store 提前加载避免页面闪烁),afterEach 做埋点与标题设置。注意守卫中避免重复重定向死循环与过度异步等待。

本题考察路由匹配与守卫时机的组合理解:动态/嵌套路由解决"URL ↔ 组件结构"映射,守卫解决"导航前后做什么"。回答时分别讲清机制,再对比 beforeEach/beforeResolve 的时机差异与分工(校验 vs 就绪),即为核心。

#
★★★

9. VueUse 在 Nuxt 3 Nitro 的现代取舍

VueUse 在 Nuxt 3/Nitro 环境下的使用有哪些取舍?哪些 API 适合、哪些需要规避?

  • VueUse 的 SSR 兼容性标记(SSR 安全/需客户端)
  • 浏览器专属 API 在 Nitro 服务端的不可用性
  • Nuxt 自动导入与 VueUse 的配合

VueUse 的大多数函数是"SSR 安全"或"仅客户端"的:设计上区分了浏览器依赖(window/document 访问)——仅在客户端挂载后执行的函数(useEventListener、useMouse、useIntersectionObserver 等)在服务端渲染时安全跳过(VueUse 内部用 isClient 判断);但仍需注意:把浏览器专属结果直接用于渲染输出会导致水合不一致(服务端与客户端值不同)。Nitro 是 Node/Bun/Deno/Workers 等服务端运行时,没有 DOM,因此服务端代码中不能使用 DOM 依赖的 VueUse 函数;服务端场景可用响应式基础工具(computed/ref 包装、useStorage 的适配层需配置驱动)与 Nuxt 生态替代(useFetch/useAsyncData 替代请求类逻辑)。现代取舍:客户端组件中放心使用浏览器相关 VueUse(配合 ClientOnly 或 onMounted);服务端与共享逻辑中只使用纯响应式工具,把请求/存储交给 Nitro/Nuxt 内置能力;利用 Nuxt 自动导入减少显式 import,注意同名冲突(如 VueUse 的 useFetch 与 Nuxt 的 useFetch 需显式别名)。

本题考察"组合式工具库 × 同构环境"的边界:核心是 VueUse 的 SSR 安全设计与浏览器依赖的规避。回答时说明 VueUse 的双轨设计(isClient 判断)、Nitro 无 DOM 的约束、以及 Nuxt 生态替代方案,即完整。

#
★★★

10. Nuxt 的模块机制(nuxt.config.ts) 在国际化/可访问性的工程取舍

Nuxt 的模块机制(nuxt.config.ts 的 modules)如何支撑国际化与可访问性?工程取舍是什么?

  • nuxt.config.ts 的 modules 声明与模块生命周期
  • 国际化模块(@nuxtjs/i18n)的路由、语言切换与 SEO
  • 可访问性模块与自定义模块的扩展方式

Nuxt 模块是通过 nuxt.config.ts 的 modules 数组声明的扩展包,模块在构建期接管配置合并、Nitro 扩展、组件/插件注册与运行时 hook——生态能力(国际化、SEO、安全、状态等)都以模块形态交付。国际化:@nuxtjs/i18n 模块提供多语言路由(前缀/域策略)、语言切换 composable、翻译资源管理与 SEO(hreflang、alternate)一体化能力,比手写 i18n 路由体系成本低且一致性好;取舍是按需求选策略(前缀 vs cookie 探测)、控制语言包体积(懒加载)。可访问性:可选用模块(如 @nuxtjs/a11y 类工具)或自定义模块注入全局 a11y 逻辑(跳过链接、焦点管理、语言属性注入);模块机制的价值是"跨项目复用 + 配置化",团队可把内部规范(无障碍检查、组件库接入)封装为私有模块。取舍原则:通用生态能力优先用成熟模块(更新与社区保障),业务特有逻辑用自定义模块或直接组合式 API 实现,避免"为了模块而模块"的过度抽象。

本题考察 Nuxt 模块体系的工程定位:模块 = 构建期 + 运行时的可复用扩展单元。回答时以 i18n/a11y 为例说明模块如何交付完整能力(配置、路由、composable、hook),并给出"生态模块 vs 自定义模块 vs 直接实现"的取舍标准,即完整。

#
★★★

11. Vue Router 数据加载(beforeRouteEnter/navigation guards)

Vue Router 中如何在导航守卫中进行数据加载?beforeRouteEnter 与组合式数据预取的工程实践是什么?

  • beforeRouteEnter 无法访问 this(组件未创建)的限制
  • 通过回调 next(vm => ...) 访问组件实例
  • 组合式 onBeforeRouteUpdate 与守卫中预取数据

Vue Router 3 的经典模式是 beforeRouteEnter:组件实例尚未创建,守卫中无法访问 this,但可通过 next(vm => vm.loadData()) 回调在组件挂载后执行数据加载;它适合"进入页面必须加载数据"的场景,配合组件的 loading/error 状态。Vue Router 4 + 组合式 API 的现代实践:用 onBeforeRouteUpdate/onBeforeRouteLeave 在组件内注册守卫(可访问组件上下文),数据预取有两种路线——路由级:在全局 beforeEach/beforeResolve 中 await 数据请求(配合 store),确保导航完成前数据就绪,避免页面闪现加载态;组件级:进入后按需加载(onMounted/useAsyncData 模式),体验更简单但首帧可能空态。工程要点:预取与守卫的重定向协作(数据失败时 return false 或跳错误页)、请求竞态与取消(AbortController)、把加载逻辑封装为 composable 统一 loading/error 状态、SSR 下使用 Nuxt useFetch 等 SSR 数据层保证水合一致。

本题考察"导航守卫中的数据流":关键是区分"导航完成前预取"(守卫 await + store)与"组件挂载后加载"(onMounted)两条路线及其取舍。回答时说明 beforeRouteEnter 的 this 限制与 next(vm) 回调、组合式守卫的用法、以及错误/竞态/SSR 的协作细节,即完整。

#
★★★

12. Pinia 的 getActivePinia 与 SSR 多个 Pinia 实例的隔离

getActivePinia 是什么?SSR 场景下多个 Pinia 实例如何隔离?

  • getActivePinia 获取当前活动 Pinia 实例
  • setActivePinia 在测试与隔离场景的切换
  • SSR 每请求独立 Pinia 实例避免状态串扰

getActivePinia() 返回"当前活动"的 Pinia 实例——即最近一次通过 app.use(pinia) 安装或 setActivePinia() 显式设置的实例;useStore() 默认从活动实例解析 store。setActivePinia() 用于切换活动实例,常见于单元测试(每测试用例创建独立实例)与隔离场景。SSR 的关键问题是"状态串扰":若所有请求共享同一个 Pinia 实例,请求 A 写入的 state 会泄漏给请求 B。因此 SSR 实践是"每请求创建独立实例":在服务端渲染每个请求时 new Pinia() 并安装到该请求的应用实例(Nuxt 内部即此模式),请求结束时实例随响应释放;客户端水合时用服务端序列化的 state 重建(pinia.state.value 反序列化),实现"服务端计算的状态 → 客户端初始状态"的一致传递。多实例管理要点:显式向 useStore 传入 pinia 实例(useStore(id, pinia))可脱离"活动实例"假设,保证多实例并存时引用正确。

本题考察 Pinia 的实例模型与同构一致性:getActivePinia 是"当前实例"的解析入口,SSR 的核心纪律是"每请求一实例 + 序列化水合"。回答时讲清活动实例机制、请求级实例隔离的原因与做法、以及水合状态传递,即完整。

#
★★

13. Vue Router 的别名、命名视图、动态路由匹配 :pathMatch(.) 的工程价值

Vue Router 的别名(alias)、命名视图(named views)与 :pathMatch(.) 动态匹配各自有什么工程价值?

  • alias 让多个 URL 映射同一路由组件
  • 命名视图在一个路由下渲染多个
  • :pathMatch(.) 捕获任意剩余路径(404 与嵌套路径)

alias 允许为同一路由声明多个可访问 URL(alias: '/profile' 与 /user/profile 都渲染同一组件),适合"短路径别名、旧 URL 兼容、多语言路径映射",且组件实例不重复创建(同一路由记录)。命名视图通过 router-view 的 name 属性让一个路由同时渲染多个视图(如 main、sidebar、footer 各自独立组件),适合复杂布局——同一 URL 不同区域的组件组合,无需嵌套路由硬编码层级。:pathMatch(.) 是 catch-all 参数路由:捕获剩余所有路径片段(数组形式保留层级),用于 404 页面、多级动态路径(如文件路径 /docs/:pathMatch(.))与通配重定向。工程价值:别名做 URL 兼容与语义化,命名视图做布局解耦,catch-all 做兜底与多级路由——三者配合可构建"灵活 URL + 复合布局 + 完备兜底"的路由体系。注意 catch-all 需放在路由表末尾避免抢占正常匹配,且 404 页面内部不应再匹配到动态路由。

本题考察路由高级特性的用途:alias(URL 复用)、命名视图(布局组合)、catch-all(兜底/多级)。回答时分别给出机制与场景,强调 catch-all 的匹配顺序纪律与命名视图的布局价值,即完整。

#
★★

14. Pinia $subscribe/$onAction 在调试与日志的工程价值

Pinia 的 $subscribe 与 $onAction 在调试与日志场景有什么工程价值?如何使用?

  • $subscribe 监听 state 变化(含 patch),记录变更轨迹
  • $onAction 拦截 action 调用(before/after/onError),记录调用参数与结果
  • 调试日志、埋点、审计的落地方式

$subscribe(cb, options) 订阅 store state 的变化:cb 收到 mutation 信息(type 为 direct 或 patch object,storeId,payload),可用于"变更日志"——记录谁在何时改了什么状态,配合 flush: 'sync' 保证顺序精确,适合审计与调试回放。$onAction(cb) 拦截该 store 所有 action 调用:cb 参数含 name、args、store,返回的 after/onError 注册成功与失败回调(可拿到返回值/错误),用于记录"操作日志"(调用参数、耗时、结果、异常),也用于埋点与埋点链路透传(context 传递 trace id)。工程价值:两者构成 Pinia 层的可观测性——不侵入业务代码即可获得"状态变更流 + 操作调用流"两份日志,排查问题时定位"哪个操作改坏了状态";配合 pinia 插件机制可统一注册(所有 store 自动启用日志),按环境开关(生产只记关键事件)。注意高频变更的日志开销与脱敏(不记录敏感字段)。

本题考察 Pinia 的观测 API 在可观测性中的应用:$subscribe 管"状态流",$onAction 管"操作流"。回答时说明两者的回调签名与时机(含 after/onError)、日志与埋点落地方式、以及插件化统一接入与性能/脱敏注意,即完整。

#
★★

15. Pinia 与 Vuex 4 的迁移与能力对比

Pinia 与 Vuex 4 相比有哪些能力差异?从 Vuex 迁移到 Pinia 的路径与要点是什么?

  • 结构差异:mutations 的移除、直接修改 state
  • TypeScript 支持与模块化(无嵌套 modules)
  • 组合式 API 的整合与 store 组织

核心差异:Pinia 移除了 mutations——actions 内直接修改 state(无需 commit),样板更少且与组合式 API 一致;类型推导是设计目标(useStore 返回完整类型,无需手写类型体操);模块体系改为"扁平多 store"(无嵌套 modules,避免命名空间与类型混乱),store 间通过 useOtherStore 直接协作。能力上 Pinia 提供 $reset/$subscribe/$onAction/插件机制,DevTools 支持同样完整,且是 Vue 官方推荐状态库(Vuex 进入维护模式)。迁移路径:把 Vuex 的 modules 拆为多个 Pinia store(保留 id 命名空间语义)、mutations 中的逻辑并入对应 actions(同步逻辑可直接在 action 内改 state)、getters 映射为 Pinia getters(接收 state/getters 参数,this 改为显式参数)、组件内 this.$store.commit/dispatch 改为 useStore 的 action 调用。要点:注意共享可变模块状态与跨 module 引用的重构、测试同步更新(mount 时注入 pinia 实例)、以及迁移期间新旧库可并存(渐进迁移)。

本题考察状态库演进的理解:回答以"mutations 移除、扁平 store、类型推导"三个结构性差异为核心,再给迁移步骤(拆 store、并 actions、改调用)与渐进迁移策略,即完整。

#
★★

16. Vue Router 4 的导航守卫(全局、路由独享、组件内)

Vue Router 4 的全局、路由独享、组件内三类导航守卫分别如何使用?执行顺序是什么?

  • 全局守卫:beforeEach/beforeResolve/afterEach
  • 路由独享守卫:beforeEnter
  • 组件内守卫:beforeRouteEnter/Update/Leave 与组合式版本

全局守卫在 router 实例上注册:beforeEach(导航触发后最先执行,用于鉴权、重定向)、beforeResolve(异步组件与组件内守卫解析完成后执行,用于就绪校验)、afterEach(导航确认后执行,无取消能力,用于埋点、标题设置)。路由独享守卫 beforeEnter 在路由配置内声明,只对该路由生效(含其直接子路由匹配时),适合页面级权限。组件内守卫三个钩子:beforeRouteEnter(进入前,实例未创建)、beforeRouteUpdate(参数变化复用组件时)、beforeRouteLeave(离开前,可做保存/确认),组合式 API 对应 onBeforeRouteEnter/onBeforeRouteUpdate/onBeforeRouteLeave。执行顺序:导航触发 → 全局 beforeEach → 路由独享 beforeEnter(按嵌套父→子)→ 组件内 beforeRouteEnter → 异步路由组件解析 → 全局 beforeResolve → 导航确认 → afterEach → DOM 更新。守卫返回值:return false 取消,return 路由对象重定向,返回值或 throw 中断(Vue Router 4 不再使用 next 参数)。

本题考察守卫体系的全貌与顺序:回答关键是"分层注册 + 完整时序"。先分别说明三类守卫的注册方式与职责,再按执行顺序串联(beforeEach → beforeEnter → beforeRouteEnter → resolve → afterEach),并强调 Vue Router 4 的 return 契约替代 next,即完整。

#
★★

17. Vue Router 4 的 meta 字段在权限与标题管理的工程应用

Vue Router 4 的 meta 字段在权限控制与页面标题管理中有哪些工程应用?

  • meta 的定义与继承(嵌套路由父级合并)
  • 守卫中读取 meta 做权限校验与重定向
  • 标题、面包屑、埋点等页面元信息

路由配置的 meta 字段存放自定义元信息(如 requiresAuth、roles、title、breadcrumb、keepAlive、埋点标识),嵌套路由匹配时子路由的 meta 与父级合并(路由记录链上的 meta 全部可读),组件内通过 useRoute().meta 或 route.matched 遍历访问。权限应用:全局 beforeEach 中读取 to.meta.requiresAuth/roles,未登录或无权限时重定向登录页/403,实现"配置化权限"而非在各组件重复判断;标题管理:afterEach 或组件内读取 meta.title 设置 document.title(可拼接站点名),配合 i18n 键实现多语言标题;面包屑:由 matched 数组逐级 meta.title 生成。类型安全:通过 declare module 'vue-router' 扩展 RouteMeta 接口,让 meta 字段获得类型检查与补全。注意 meta 合并语义(数组/对象类型按路由链合并规则)与动态路由 meta 的一致管理。

本题考察 meta 作为"路由元数据层"的应用:回答围绕"配置化驱动"展开——权限(守卫读 meta)、标题(afterEach 设置)、面包屑(matched 遍历)、类型扩展(RouteMeta 增强),并说明嵌套合并语义,即完整。

#
★★

18. Pinia 的插件机制在持久化(pinia-plugin-persistedstate)

Pinia 的插件机制如何实现状态持久化?pinia-plugin-persistedstate 的工作原理与取舍是什么?

  • 插件在 store 创建时注入的能力(context:pinia/app/options/store)
  • 持久化插件订阅 state 变化并写存储,初始化时读取恢复
  • 配置化:key、pick 字段、storage 类型、序列化器

pinia-plugin-persistedstate 通过 pinia.use() 注册:store 创建时读取配置(persist 选项)决定是否持久化——插件利用 $subscribe 监听 state 变化并序列化写入配置的 storage(默认 localStorage,可换 sessionStorage/自定义),store 初始化时从存储反序列化并合并回 state,实现"刷新不丢状态"。配置支持按字段选择(pick/omit)、自定义 key 前缀、自定义序列化(JSON 之外的加密/压缩)。取舍与注意:持久化数据体积应小(大数据用 pick 裁剪)、敏感数据不入存储(token 安全性评估);多标签页/多窗口的同步需 storage 事件配合,多实例写入可能相互覆盖;数据版本与结构变更需迁移策略(版本号 + 迁移函数),读取失败(损坏数据)需兜底回退默认 state;SSR 下客户端持久化需在挂载后生效(避免水合不一致)。插件机制本身的价值:持久化能力与业务 store 解耦,按需开启(单个 store 配置 persist),便于统一治理与测试。

本题考察 Pinia 插件模式的具体落地:回答按"机制($subscribe 写 + 初始化读)→ 配置(字段/key/storage)→ 工程注意(体积、安全、多标签、版本迁移、SSR)"三层展开,体现插件解耦的价值与边界,即完整。

#
★★

19. Pinia 与 Vue Router 的状态管理协作(路由参数转 store)

Pinia 与 Vue Router 如何协作?"路由参数转 store"模式的工程实践是什么?

  • store 中读取 route 参数与响应式同步
  • 路由参数驱动数据请求与状态更新的模式
  • 参数变化的监听与竞态处理

协作模式:store 在 setup 中通过 useRoute() 读取当前路由参数,把"URL 状态"转化为"业务状态"——例如列表页把 query(page、keyword、filter)同步进 store 的过滤状态,用 watch(() => route.query) 监听变化并驱动 store action 拉取数据,实现"URL 驱动数据流":分享链接、前进后退、刷新都还原同一视图状态。要点:参数变化与请求竞态——用 AbortController 或请求序号取消过期请求;同步方向要明确(URL → store 单向为主,避免双向死循环;store 变化改 URL 用 router.replace 并去掉重复触发);首次进入时用 route 初值初始化 store(immediate watch 或初始化读取)。分工:URL 中的"可分享、可回退"状态(分页、筛选、搜索词)放 query,会话级/页面内状态放 store,避免 URL 膨胀;路由守卫中也可预取数据写入 store(beforeResolve 模式)减少等待。SSR 下注意 route 在服务端的同步获取与 store 的水合一致性。

本题考察"URL 状态与全局状态"的联动建模:核心是单向同步(URL → store → 数据)与竞态治理。回答时给出 watch route.query + action 拉数据的模式、竞态/重复触发处理、URL 与 store 的分工原则,即完整。

#
★★

20. Pinia 在 SSR 模式下的状态序列化与水合工程边界

Pinia 在 SSR 模式下的状态序列化与水合有什么工程边界?如何保证一致?

  • 每请求独立 Pinia 实例与 state 收集
  • 序列化到 payload 与客户端反序列化重建
  • 可序列化限制(函数、代理、循环引用)

SSR 边界:每个请求创建独立 Pinia 实例(避免请求间串扰),服务端渲染过程中 store 的 state 被填充(数据预取写入),渲染结束后把 pinia.state.value 序列化(JSON)注入页面 payload;客户端启动时创建新 Pinia 实例并反序列化恢复 state,组件水合时读到与服务端一致的数据。工程要点:state 必须可 JSON 序列化——函数、Proxy、类实例、循环引用需要规避或转换(序列化前清洗、用普通对象建模),否则反序列化后状态损坏或不一致;敏感数据(token 等)避免进 payload 或加密;payload 体积控制(只序列化渲染所需状态,避免整库状态膨胀首屏字节)。水合一致性:任何"仅客户端生成"的状态(随机值、Date、localStorage 读取)会导致服务端与客户端初始 state 不一致,从而产生水合差异——此类状态应在挂载后(onMounted)再写入 store;配合 Nuxt 的 useFetch/useAsyncData payload 机制可统一管理数据状态。调试时对比服务端与客户端序列化 JSON 是否一致。

本题考察 SSR 状态传递的完整链路:每请求实例 → 序列化注入 → 客户端重建 → 一致性保证。回答围绕"可序列化约束"与"一致性纪律"(客户端专属状态后置、敏感数据过滤、体积控制)展开,即覆盖工程边界。

#
★★

21. Vue Router 4 的 与 的现代应用

Vue Router 4 的 与 在现代应用中的用法与工程要点是什么?

  • router-link 的 to/active-class/exact 等 props 与事件
  • router-view 的 v-slot(Component、route)与 keep-alive/transition 组合
  • 滚动行为、无障碍(active 状态)

本题考察路由渲染与导航的基础组件在现代用法:router-link 管"导航 + 状态样式",router-view 管"渲染 + 与 KeepAlive/Transition 组合"。回答时说明两者的插槽 API、组合模式(v-slot + component :is + keep-alive)、以及 active/无障碍/命名导航要点,即完整。

#
★★

22. Pinia 的 getters 在派生状态与计算缓存的现代应用

Pinia 的 getters 如何实现派生状态与计算缓存?现代应用中有哪些要点?

  • getters 接收 state(可选 getters)参数,返回派生值
  • 基于 computed 的缓存:依赖未变不重算
  • 返回函数的 getter 实现传参派生

Pinia 的 getters 是 store 内的派生状态:定义时接收 state 与(可选)其他 getters 参数,内部基于 computed 实现——只有依赖的 state 变化时才重新计算并缓存结果,多次读取不重复计算(如过滤列表、统计汇总、权限组合)。传参场景用"返回函数的 getter":getter 返回一个函数(如 getById: (state) => (id) => state.items.find(...)),调用方传参取值;注意此类 getter 不享受 computed 缓存(每次调用执行函数体),适合小规模查找。现代应用要点:把"组件内重复计算"上移到 store(单一实现、跨组件复用、随 state 更新一致);getter 中避免副作用与异步(保持纯函数,异步用 action);与组件 computed 的分工——单个组件专用派生放组件内,多组件共享或依赖多个 state 字段的派生放 getter;SSR/测试中 getter 同样可独立求值验证。getter 也可访问其他 store(useOtherStore)实现跨 store 派生。

本题考察 getters 的机制与复用:核心是"computed 缓存语义"与"传参 getter 的取舍"。回答时说明两种形态(值派生 vs 函数派生)及其缓存差异、上移复用原则与纯函数纪律,即完整。

#
★★

23. Pinia 的 actions 在异步操作与错误处理的工程取舍

Pinia 的 actions 如何处理异步操作与错误?工程上有哪些取舍?

  • action 中直接修改 state 与调用其他 store
  • 异步请求的 loading/error 状态建模
  • 错误传播(throw vs 返回结果)与调用方处理

Pinia action 是任意函数(同步/异步),内部可直接修改 state、调用其他 store 的 action(useOtherStore)完成协作;异步操作的工程建模:在 state 中声明 loading/error/data 字段,action 内 try/catch/finally 更新状态——loading 开关、错误信息与数据分离存储,组件只读状态渲染,不散落请求逻辑。错误处理取舍:action 内捕获并转换为业务错误状态(如 { code, message })写入 store(UI 直接展示),或重新 throw 由调用方处理(路由守卫、跨 store 编排时需要感知失败)——原则是"错误的消费方决定是否抛出";全局错误统一上报可在插件层包装 action(onAction 的 onError 钩子统一埋点)。异步细节:竞态(快速连续调用取最后一次结果)用请求序号或 AbortController 取消;失败重试策略(指数退避)封装为可复用 action 工具;loading 状态注意并发计数(多个并发请求的 loading 合并)。SSR 下 action 在服务端执行后状态随 payload 水合,需保证幂等与可序列化。

本题考察异步状态管理的建模能力:回答围绕"状态字段建模(loading/error/data)→ 错误传播策略 → 竞态与重试 → 插件统一上报"展开,给出可复用的 action 模式,即完整。

#

24. Vue Router 4 的路由组件缓存()在多步骤表单的应用

缓存路由组件在多步骤表单中如何应用?要点与取舍是什么?

  • router-view 与 keep-alive 组合缓存路由组件
  • 多步骤表单步骤间状态保留
  • include/exclude 与步骤维度的缓存控制

多步骤表单(向导式)的核心诉求是"步骤切换不丢已填数据":用 缓存各步骤组件,步骤 A → B → A 切换时 A 的实例与表单状态保留(activated/deactivated 钩子维护)。要点:缓存范围控制——include 按组件 name 只缓存表单步骤页(避免缓存无关页面)、配合路由 meta 动态生成 include 列表;:key 管理——同一路由不同业务(不同表单实例)用 key 区分缓存单元;数据落库:最终提交时收集各步骤状态(store 或表单数据聚合),提交成功后移除缓存(include 剔除或强制重置,用 reset 函数/清除 key)避免"已提交数据再次出现";离开确认:未提交离开步骤时用 onBeforeRouteLeave 或弹窗拦截。取舍:缓存以内存换体验,步骤多/数据大时注意内存;更推荐"状态提升"方案——表单数据存 store(或 Pinia),组件只做渲染,切换步骤不依赖缓存也天然保留,缓存作为兜底(如保留滚动与局部 DOM 状态)。

本题考察路由缓存与业务状态的结合:核心是"缓存实例 vs 状态提升"两种方案的选择。回答时给出 keep-alive 组合的配置与钩子用法、缓存失效时机(提交后清理)、以及状态提升的替代方案与取舍,即完整。

#

25. Pinia 的测试工具(@pinia/testing)在单元测试的工程实践

@pinia/testing 在单元测试中如何实践?它与真实 Pinia 的差异与价值是什么?

  • createTestingPinia 创建测试实例(stub actions、mock state)
  • 组件测试中挂载测试 pinia 与断言 state/action
  • stubActions 模式下 action 行为的控制

@pinia/testing 提供 createTestingPinia():创建可注入测试环境的 Pinia 实例,默认 stubActions: true——store 的 actions 被替换为 spy(不执行真实逻辑),测试通过 vi.spyOn 断言 action 被调用、或重新定义其行为(返回 mock 数据);初始 state 可通过 initialState 参数预设,也可在测试中直接修改 store 状态。组件测试中:mount 组件时 provide 测试 pinia(global.plugins: [testingPinia]),组件内 useStore 解析到测试实例,然后断言"渲染依赖 state 的 UI"与"交互触发 action 及参数"。价值:状态与行为解耦——不跑真实请求即可测试组件与 store 的协作契约;单元测试 store 本身时可用真实 Pinia(测 state/getters/actions 逻辑)。实践要点:测试间重置(setActivePinia 或重新 createTestingPinia)避免状态串扰、异步 action 用 await 断言、插件(如持久化)在测试中按需禁用、与 Vitest 的 mock 体系(vi.fn/vi.mock)配合控制外部依赖。

本题考察状态管理层的测试策略:核心是"stub actions + 可控 state"让组件测试聚焦交互契约。回答时说明 createTestingPinia 的用法(stubActions、initialState)、与 Vue Test Utils 的挂载配合、以及 store 自身单测与集成测试的分工,即完整。

#

26. Vue Router 4 的历史模式(createWebHistory)

Vue Router 4 的历史模式有哪些?createWebHistory 的机制与工程要点是什么?

  • createWebHistory / createWebHashHistory / createMemoryHistory 的差异
  • history API(pushState/replaceState/popstate)驱动的导航
  • 服务端配置(SPA fallback)与 404 处理

Vue Router 4 提供三种历史模式:createWebHistory 基于 History API(pushState/replaceState 改变 URL 不刷新页面,popstate 响应前进后退),URL 干净美观,是生产首选;createWebHashHistory 用 # 后的 hash 片段承载路由(变化不触发服务器请求),适合无法配置服务端回退的静态部署;createMemoryHistory 不操作浏览器地址栏(内存中维护历史栈),用于 SSR、测试与无 UI 环境。createWebHistory 的工程要点:必须配置服务端 SPA fallback——所有路径都返回 index.html(否则直接访问 /detail/1 会 404),并对真实存在的静态资源正确响应;部署在子路径时用 base 配置(如 base: '/app/');404 页用 catch-all 路由承接前端未匹配路径(服务端返回 200 由前端渲染 404 组件,或按需配合服务端 404 状态);SSR 环境需用 createMemoryHistory 预渲染路由,水合后再切到浏览器历史模式;注意浏览器兼容(旧浏览器需 polyfill)与 popstate 对 pushState 的监听差异。

本题考察路由历史模式的选型与部署配套:核心是"history 模式的美观 URL 依赖服务端 fallback"。回答时对比三种模式的使用场景,重点讲 createWebHistory 的服务端配置、base 子路径与 404 处理、以及 SSR 下的 memory history 选择,即完整。