跳到主要内容
极客日志极客日志面向AI+效率的开发者社区
首页博客GitHub 精选镜像工具UI配色美学隐私政策关于联系
搜索内容 / 工具 / 仓库 / 镜像...⌘K搜索
注册
博客列表
JavaScript大前端

Vue Router 进阶使用指南:导航守卫与状态管理

详细介绍 Vue Router 的进阶用法,涵盖导航守卫(组件内、路由独享、全局钩子)、嵌套路由、重定向与别名配置及 History 模式选择。同时讲解路由元信息 meta 的使用,并对比 Vuex 与 Pinia 状态管理库,提供 Pinia 基础配置、持久化插件及 Cookie 存储示例。

二进制发布于 2026/4/6更新于 2026/5/2746 浏览
Vue Router 进阶使用指南:导航守卫与状态管理

深入使用

导航守卫

导航守卫用于在路由跳转前、跳转后或解析过程中,添加自定义的逻辑处理,例如权限验证。

  • to 和 from 是即将进入的目标路由和当前导航正要离开的路由
  • next 是一个函数,该函数用于控制路由的跳转。
  • next():继续执行路由。
  • next(false):中断当前路由,如果浏览器的 URL 改变了,那么 URL 会回到 from 路由。
  • next('/path'):跳转到指定路径。
  • next(error):将控制权交给 router.onError()。

组件内守卫

export default {
  beforeRouteEnter(to, from, next) {
    // 在路由进入前调用
    next();
  },
  beforeRouteUpdate(to, from, next) {
    // 在当前路由改变,但组件被复用时调用
    next();
  },
  beforeRouteLeave(to, from, next) {
    // 在路由离开前调用
    next();
  }
};

路由独享守卫

const routes = [
  { 
    path: '/admin', 
    component: Admin,
    beforeEnter: (to, from, next) => {
      // 仅管理员可访问
      if (isAdmin()) {
        next();
      } else {
        next('/login');
      }
    }
  }
];

全局后置钩子 全局后置钩子通过 router.afterEach 方法设置,它不会接收 next 函数也不会改变导航本身:

router.afterEach((to, from) => {
  // 在这里你可以访问路由守卫结束后的状态,但不能改变状态。
  console.log('路由已切换');
  // 例如,记录日志或者统计页面访问等。
});

全局解析守卫 全局解析守卫通过 router.beforeResolve 方法设置,它在所有组件内守卫和异步路由组件被解析之后调用。

router.beforeResolve((to, from, next) => {
  // 类似于 beforeEach,但是在这个守卫中,所有组件内守卫和异步路由组件被解析之后调用。
});

全局前置守卫

router.beforeEach((to, from, next) => {
  // 例如,验证用户是否已登录
  if (to.path === '/protected' && !isLoggedIn()) {
    next('/login'); // 跳转到指定路径
  } else {
    next(); // 继续执行路由
  }
});

嵌套路由

嵌套路由用于构建具有层级关系的页面结构,即在一个组件内部再嵌套另一个路由视图。

详见:传送门

在父组件模板中

<template>
  <div>
    <h2>用户页面</h2>
    <router-view></router-view> <!-- 渲染子路由组件 -->
  </div>
</template>

定义嵌套路由

const routes = [
  { 
    path: '/user', 
    component: User, 
    children: [
      { 
        // 当/user/profile 匹配成功,UserProfile 将被渲染到 User 的<router-view>内部
        path: 'profile', 
        component: UserProfile 
      },
      { 
        path: 'posts', 
        component: UserPosts 
      }
    ]
  }
];

注意,以 / 开头的嵌套路径将被视为根路径。这允许你利用组件嵌套,而不必使用嵌套的 URL

重定向与别名

重定向:也是通过 routes 配置来完成

  • 导航守卫并没有应用在跳转路由上,而仅仅应用在其目标上。在上面的例子中,在 /home 路由中添加 beforeEnter 守卫不会有任何效果。
  • 在写 redirect 的时候,可以省略 component 配置,因为它从来没有被直接访问过,所以没有组件要渲染。唯一的例外是嵌套路由:如果一个路由记录有 children 和 redirect 属性,它也应该有 component 属性。

相对重定向:重定向到相对位置

const routes = [
  {
    // 将总是把/users/123/posts 重定向到/users/123/profile。
    path: '/users/:id/posts',
    redirect: to => {
      // 该函数接收目标路由作为参数
      return to.path.replace(/posts$/, 'profile');
    }
  }
]

示例:

const routes = [
  { path: '/home', redirect: '/' }
]
const routes = [
  { path: '/home', redirect: { name: 'homepage' } }
]
const routes = [
  {
    // /search/screens -> /search?q=screens
    path: '/search/:searchText',
    redirect: to => {
      // 方法接收目标路由作为参数
      // return 重定向的字符串路径/路径对象
      return { 
        path: '/search', 
        query: { q: to.params.searchText } 
      };
    }
  },
  { path: '/search', /* ... */ }
]

注意

别名

如果路由有参数,需确保在任何绝对别名中包含它们:

const routes = [
  { 
    path: '/users/:id', 
    component: UsersByIdLayout, 
    children: [
      // 为这 3 个 URL(/users/24、/users/24/profile、/24)呈现 UserDetails
      {
        path: 'profile', 
        component: UserDetails, 
        alias: ['/:id', '']
      }
    ]
  }
]

通过别名,可以自由地将 UI 结构映射到一个任意的 URL,而不受配置的嵌套结构的限制。使别名以 / 开头,以使嵌套路径中的路径成为绝对路径。甚至可以将两者结合起来,用一个数组提供多个别名:

const routes = [
  { 
    path: '/users', 
    component: UsersLayout, 
    children: [
      // 为这 3 个 URL(/users、/users/list、/people)呈现 UserList
      {
        path: '', 
        component: UserList, 
        alias: ['/people', 'list']
      }
    ]
  }
]

**将 / 别名为 /home,意味着当用户访问 /home 时,URL 仍然是 /home,但会被匹配为用户正在访问 /。**重定向是指当用户访问 /home 时,URL 会被 / 替换,然后匹配成 /。

const routes = [
  { path: '/', component: Homepage, alias: '/home' }
]

history 配置:指定历史模式

  • 内部传递的实际 URL 之前会加一个井号(#)(如 http://example.com/#/home)

  • 无需服务器配置(所有 URL,包括是不存在的,都不会被发送到服务器),适合纯前端单页应用(SPA)

  • 不过,它在 SEO 中确实有不好的影响。如果担心这个问题,可以使用 HTML5 模式。

  • createWebHistory():history 模式 / HTML5 模式

    • url 更简洁(如 http://example.com/home),无 #
    • 需要服务器支持(避免 404 错误,需配置回退到 index.html)
    • 适合需要 seo 或对 url 美观有要求的项目:
  • createMemoryHistory():Memory 模式

    • Memory 模式不会假定自己处于浏览器环境,因此不会与 URL 交互也不会自动触发初始导航
    • 需要在调用 app.use(router) 之后手动 push 到初始导航
    • 虽然不推荐,但仍可以在浏览器应用程序中使用此模式注意:它不会有历史记录,这意味着无法后退或前进
    • 非常适合 Node 环境和 SSR

createWebHashHistory():Hash 模式(默认模式)

import { createRouter, createWebHashHistory } from 'vue-router'
const router = createRouter({ 
  history: createWebHashHistory(), 
  routes: [...] 
})

路由元信息(meta)

路由配置中可以添加元信息(meta),例如权限控制、页面标题等。

全局导航守卫中使用:

router.beforeEach((to, from) => {
  if (to.meta.requiresAuth && !isAuthenticated()) {
    return { name: 'Login' };
  }
});

获取元信息:

<script setup>
import { useRoute } from 'vue-router';
const route = useRoute();
console.log(route.meta.title); // "控制面板"
</script>

路由配置:

const routes = [
  { 
    path: '/dashboard', 
    name: 'Dashboard', 
    component: Dashboard, 
    meta: { 
      requiresAuth: true, 
      title: '控制面板' 
    }
  }
];

拓展

状态管理(Pinia / Vuex)

Pinia / Vuex 介绍

对于复杂或跨页面的数据传递,推荐使用状态管理库(Pinia/Vuex)。

  • Vuex:Vuex 是 Vue.js 官方的状态管理库。采用了 Flux 的思想,提供了一个集中式存储,允许组件以不同的方式共享状态。核心概念:
    • State: 应用的状态存储。
    • Getters: 类似于计算属性,用于计算基于状态的派生状态。
    • Mutations: 处理状态的唯一方式,直接修改状态。
    • Actions: 进行异步操作,并提交 Mutations。
  • Pinia:Pinia 是一个新兴的状态管理库,也是 Vue.js 的官方推荐替代方案。它为 Vue 3 提供了一种更简单、更具灵活性的状态管理方式与 Vuex 相比,Pinia 在设计上更现代化,支持 Composition API,使得开发者在使用时更加方便。核心概念:
    • Store: 状态存储的基本单位,通过建立一个或多个 Store 来管理状态。
    • State: 用于保存应用的响应式状态。
    • Getters: 计算属性的延伸,基于状态计算派生值。
    • Actions: 包含了执行异步操作的行为和直接修改状态的方法。
Vuex vs Pinia
  • API 和易用性
    • Vuex:采用认证的 Flux 风格,有一定的学习曲线,需要掌握多个概念(状态、getter、mutation、action)。对于小型应用来说,可能会显得过于复杂。
    • Pinia:设计更为简单,结合了 Composition API,让开发者能够更直观地管理状态。尤其是 Vue 3 的 Setup 语法糖,使用更加直观。
  • 响应式
    • Vuex:响应式总是要依赖于 Vue 的响应式系统,并且有多种约定(例如 Mutation),使用中需要更小心。
    • Pinia:完全基于 Vue 3 的响应式系统,状态变化后组件自动更新,无需额外的处理。
  • DevTools 支持
    • Vuex:在 Vue DevTools 中支持非常好,可以很方便地进行状态的查看和时间旅行调试。
    • Pinia:同样也支持 Vue DevTools,且整体使用体验更友好。
  • 社区支持和生态
    • Vuex:由于是官方库,资料和插件相对丰富,很多现有的项目都是基于 Vuex 的。
    • Pinia:作为新兴库,其社区支持还在不断扩大,函数式编程风格吸引了一部分开发者,但整体生态仍需时间发展。

总结

Vuex 和 Pinia 各有优缺点,选择哪个库取决于你的项目需求和个人偏好。如果你正在开发一个较大型的应用,且已有 Vuex 的使用经验,那么继续使用 Vuex 可能是一个不错的选择。而如果你想要尝试一种更简单、现代化的方式,那么 Pinia 无疑是个值得尝试的选项。

Pinia 基本使用
  • pinia-plugin-persistedstate 为 pinia 的数据持久化插件

使用 Pinia

<template>
  <div>
    <p>Count: {{ count }}</p>
    <p>Double Count: {{ doubleCount }}</p>
    <button @click="increment">Increment</button>
    <button @click="incrementAsync">Increment Async</button>
  </div>
</template>
<script setup lang="ts">
import { computed } from "vue";
import { useUserStore } from '@/utils/store.js';

const counterStore = useUserStore();
const count = computed(() => counterStore.count);
const doubleCount = computed(() => counterStore.doubleCount);
const increment = () => { counterStore.increment(); }
const incrementAsync = async () => { await counterStore.incrementAsync(); }
</script>

创建一个 Store

// store.js
import { defineStore } from 'pinia';

export const useCounterStore = defineStore('counter', {
  state: () => ({ count: 0 }),
  getters: {
    doubleCount(state) {
      return state.count * 2;
    }
  },
  actions: {
    increment() {
      this.count++;
    },
    async incrementAsync() {
      await new Promise((resolve) => setTimeout(resolve, 1000));
      this.count++;
    }
  },
  persist: {
    enabled: true, // 启用持久化
    storage: window.localStorage, // 存储到 localStorage(默认)/sessionStorage
  }
});

在 main.ts 或 main.js 中初始化

import { createApp } from 'vue';
import { createPinia } from 'pinia';
import { createPersistedState } from 'pinia-plugin-persistedstate';

const app = createApp(App);
// 将状态管理器 pinia 装入 app
const pinia = createPinia();
pinia.use(createPersistedState()); // 开启状态持久化
app.use(pinia);
app.mount('#app');

安装 Pinia

npm install pinia pinia-plugin-persistedstate
Pinia 使用 Cookies 存储

虽然 Cookies 主要用于存储少量数据,并且有大小限制(通常为 4KB),但在某些情况下,也可以用于简单的持久化。

使用 Cookies 进行持久化时,需要手动处理数据的读写:

export const useUserStore = defineStore('user', {
  state: () => ({ name: null, age: null }),
  actions: {
    setName(name) {
      this.name = name;
      document.cookie = `name=${name}; path=/; max-age=3600`;
    },
    getName() {
      const name = document.cookie.split('; ').find(row => row.startsWith('name='));
      if (name) {
        this.name = name.split('=')[1];
      }
    }
  }
});

目录

  1. 深入使用
  2. 导航守卫
  3. 嵌套路由
  4. 重定向与别名
  5. history 配置:指定历史模式
  6. 路由元信息(meta)
  7. 拓展
  8. 状态管理(Pinia / Vuex)
  9. Pinia / Vuex 介绍
  10. Vuex vs Pinia
  11. Pinia 基本使用
  12. Pinia 使用 Cookies 存储
  • 💰 8折买阿里云服务器限时8折了解详情
  • Magick API 一键接入全球大模型注册送1000万token查看
  • 🤖 一键搭建Deepseek满血版了解详情
  • 一键打造专属AI 智能体了解详情
极客日志微信公众号二维码

微信扫一扫,关注极客日志

微信公众号「极客日志V2」,在微信中扫描左侧二维码关注。展示文案:极客日志V2 zeeklog

更多推荐文章

查看全部
  • Node.js+Vue 宠物店管理系统设计与实现
  • Chaterm:开源 AI 智能终端与 SSH 客户端功能解析
  • 双指针算法进阶:有效三角形、两数及多数之和
  • MCP 插件配置指南:以 browser-tools-mcp 为例
  • Qt WebChannel 多方法调用导致 execCallbacks 错误的解决方案
  • Wildcard AI 服务评测:低价背后的模型真相
  • 数据结构:双向链表详解与实现
  • 大模型 Agent(智能体)核心架构与实战解析
  • 前端国际化最佳实践:让你的网站走向世界
  • 1Panel+Ollama+WebUI:打造本地AI模型的完整指南(附Gemini插件教程)
  • 使用预训练模型实现扫地机器人物品识别
  • STL stack 与 queue 底层模拟实现及算法实战
  • 基于 Trae Solo 与豆包模型构建智能点餐应用
  • Python SQLAlchemy ORM 数据库操作指南
  • Git 国内镜像源下载与安装配置指南
  • AIGC 时代 R 语言在数据科学中的应用与优势
  • To B 产品经理转型 AI 的核心策略与实施路径
  • C 语言实现顺时针旋转矩阵算法
  • 若依 (RuoYi) 低代码框架全面分析
  • DeepFace 结合 OpenCV 实现实时情绪分析

相关免费在线工具

  • Keycode 信息

    查找任何按下的键的javascript键代码、代码、位置和修饰符。 在线工具,Keycode 信息在线工具,online

  • Escape 与 Native 编解码

    JavaScript 字符串转义/反转义;Java 风格 \uXXXX(Native2Ascii)编码与解码。 在线工具,Escape 与 Native 编解码在线工具,online

  • JavaScript / HTML 格式化

    使用 Prettier 在浏览器内格式化 JavaScript 或 HTML 片段。 在线工具,JavaScript / HTML 格式化在线工具,online

  • JavaScript 压缩与混淆

    Terser 压缩、变量名混淆,或 javascript-obfuscator 高强度混淆(体积会增大)。 在线工具,JavaScript 压缩与混淆在线工具,online

  • Base64 字符串编码/解码

    将字符串编码和解码为其 Base64 格式表示形式即可。 在线工具,Base64 字符串编码/解码在线工具,online

  • Base64 文件转换器

    将字符串、文件或图像转换为其 Base64 表示形式。 在线工具,Base64 文件转换器在线工具,online