MK
摩柯社区 - 一个极简的技术知识社区
AI 面试

Vue 2与Vue 3 路由管理Vue Router的功能扩展与优化

2023-08-116.8k 阅读

Vue Router 基础回顾

在深入探讨 Vue 2 和 Vue 3 中 Vue Router 的功能扩展与优化之前,先来简单回顾一下 Vue Router 的基础概念与用法。

Vue Router 是 Vue.js 官方的路由管理器,它和 Vue.js 的核心深度集成,让构建单页面应用变得易如反掌。在一个 Vue 应用中,通过 Vue Router 可以实现页面的切换、组件的动态加载以及根据不同的 URL 展示不同的内容。

在 Vue 2 项目中,安装 Vue Router 后,通常在 router/index.js 文件中进行配置。例如:

import Vue from 'vue';
import Router from 'vue-router';
import Home from '@/components/Home.vue';
import About from '@/components/About.vue';

Vue.use(Router);

export default new Router({
  routes: [
    {
      path: '/',
      name: 'Home',
      component: Home
    },
    {
      path: '/about',
      name: 'About',
      component: About
    }
  ]
});

在上述代码中,首先引入 Vue 和 Vue Router 模块,然后通过 Vue.use(Router) 安装 Vue Router。接着定义了两条路由规则,path 表示 URL 路径,name 为路由的名称,component 则指定了该路由对应的组件。

在 Vue 组件中,使用 <router - link> 组件来创建导航链接,使用 <router - view> 组件来展示匹配路由的组件内容。例如在 App.vue 中:

<template>
  <div id="app">
    <router - link to="/">Home</router - link>
    <router - link to="/about">About</router - link>
    <router - view></router - view>
  </div>
</template>

<script>
export default {
  name: 'App'
};
</script>

<style>
/* 样式代码 */
</style>

这样,当用户点击 HomeAbout 链接时,router - view 区域会相应地展示 HomeAbout 组件的内容。

Vue 3 中使用 Vue Router 的方式在基本结构上类似,但在一些细节和语法上有所变化。例如在 Vue 3 项目中,安装 Vue Router 后,router/index.js 文件的配置如下:

import { createRouter, createWebHistory } from 'vue - router';
import Home from '@/components/Home.vue';
import About from '@/components/About.vue';

const router = createRouter({
  history: createWebHistory(),
  routes: [
    {
      path: '/',
      name: 'Home',
      component: Home
    },
    {
      path: '/about',
      name: 'About',
      component: About
    }
  ]
});

export default router;

这里通过 createRoutercreateWebHistory 来创建路由实例,createWebHistory 用于创建 HTML5 历史模式的路由。这种方式相比 Vue 2 的写法更加直观和函数式。

Vue 2 中 Vue Router 的功能扩展

路由嵌套

在实际项目中,经常会遇到页面有多层嵌套的情况,Vue Router 支持路由嵌套功能。例如,我们有一个博客应用,在文章详情页中,还可能有评论、相关文章等子页面。

首先,在 router/index.js 中定义嵌套路由:

import Vue from 'vue';
import Router from 'vue-router';
import Blog from '@/components/Blog.vue';
import Article from '@/components/Article.vue';
import Comment from '@/components/Comment.vue';
import RelatedArticle from '@/components/RelatedArticle.vue';

Vue.use(Router);

export default new Router({
  routes: [
    {
      path: '/blog',
      name: 'Blog',
      component: Blog,
      children: [
        {
          path: ':articleId',
          name: 'Article',
          component: Article,
          children: [
            {
              path: 'comment',
              name: 'Comment',
              component: Comment
            },
            {
              path:'related',
              name: 'RelatedArticle',
              component: RelatedArticle
            }
          ]
        }
      ]
    }
  ]
});

在上述代码中,Blog 路由下有 Article 子路由,Article 路由又有 CommentRelatedArticle 子路由。注意,子路由的 path 不需要以 / 开头,它会自动继承父路由的路径。

Blog.vue 组件模板中,需要添加 <router - view> 来展示子路由的内容:

<template>
  <div>
    <h1>Blog Page</h1>
    <router - view></router - view>
  </div>
</template>

<script>
export default {
  name: 'Blog'
};
</script>

<style>
/* 样式代码 */
</style>

同样,在 Article.vue 组件模板中也需要添加 <router - view> 来展示其下一级子路由的内容:

<template>
  <div>
    <h2>Article Page</h2>
    <router - view></router - view>
  </div>
</template>

<script>
export default {
  name: 'Article'
};
</script>

<style>
/* 样式代码 */
</style>

这样,当访问 /blog/123/comment 时,会依次展示 Blog 组件、Article 组件以及 Comment 组件的内容。

动态路由匹配

动态路由匹配允许我们在路由路径中使用参数,以便根据不同的参数值展示不同的内容。比如在上面的博客应用中,文章详情页的路由可以根据文章的 ID 来动态展示不同文章的内容。

router/index.js 中定义动态路由:

{
  path: '/blog/:articleId',
  name: 'Article',
  component: Article
}

Article.vue 组件中,可以通过 $route.params 来获取动态参数:

<template>
  <div>
    <h2>Article ID: {{ $route.params.articleId }}</h2>
    <!-- 文章内容展示 -->
  </div>
</template>

<script>
export default {
  name: 'Article'
};
</script>

<style>
/* 样式代码 */
</style>

这样,当访问 /blog/1/blog/2 等不同的文章 ID 路径时,Article 组件中会显示相应的文章 ID。

导航守卫

导航守卫是 Vue Router 提供的一种机制,用于在路由导航发生变化时进行一些操作,比如验证用户权限、记录路由信息等。

全局前置守卫是最常用的一种导航守卫,在 router/index.js 中定义如下:

router.beforeEach((to, from, next) => {
  const isAuthenticated = localStorage.getItem('token');
  if (to.matched.some(record => record.meta.requiresAuth) &&!isAuthenticated) {
    next('/login');
  } else {
    next();
  }
});

在上述代码中,beforeEach 会在每次路由导航前被调用。to 表示即将要进入的目标路由对象,from 表示当前导航正要离开的路由对象,next 是一个函数,调用 next() 表示放行,继续进入目标路由;调用 next('/login') 则表示重定向到 /login 路由。这里通过检查 localStorage 中是否存在 token 来判断用户是否已认证,如果目标路由的 meta 字段中有 requiresAuth 且用户未认证,则重定向到登录页面。

Vue 3 中 Vue Router 的功能扩展

新的路由创建方式

Vue 3 中使用 createRoutercreateWebHistory 等函数来创建路由实例,这种方式更加灵活和函数式。例如,除了 createWebHistory 创建 HTML5 历史模式的路由外,还可以使用 createWebHashHistory 创建哈希模式的路由:

import { createRouter, createWebHashHistory } from 'vue - router';
import Home from '@/components/Home.vue';
import About from '@/components/About.vue';

const router = createRouter({
  history: createWebHashHistory(),
  routes: [
    {
      path: '/',
      name: 'Home',
      component: Home
    },
    {
      path: '/about',
      name: 'About',
      component: About
    }
  ]
});

export default router;

哈希模式的路由 URL 中会带有 # 符号,它的优点是兼容性好,在一些不支持 HTML5 历史模式的环境中也能正常工作。

路由元信息增强

在 Vue 3 的 Vue Router 中,路由元信息(meta)的使用更加灵活和强大。例如,可以在路由配置中定义更加复杂的元信息,并且在导航守卫中更方便地使用。

router/index.js 中定义路由元信息:

const router = createRouter({
  history: createWebHistory(),
  routes: [
    {
      path: '/admin',
      name: 'Admin',
      component: Admin,
      meta: {
        requiresAuth: true,
        roles: ['admin']
      }
    }
  ]
});

在导航守卫中使用增强的元信息:

router.beforeEach((to, from, next) => {
  const isAuthenticated = localStorage.getItem('token');
  const userRole = localStorage.getItem('role');
  if (to.matched.some(record => record.meta.requiresAuth) &&!isAuthenticated) {
    next('/login');
  } else if (to.matched.some(record => record.meta.roles) &&!to.matched.some(record => record.meta.roles.includes(userRole))) {
    next('/forbidden');
  } else {
    next();
  }
});

这里不仅检查了用户是否认证,还检查了用户的角色是否符合目标路由的要求。如果用户角色不符合,就重定向到 /forbidden 页面。

路由懒加载优化

Vue 3 中路由懒加载的语法略有变化,并且在性能优化方面有更好的表现。在 Vue 2 中,路由懒加载通常使用 () => import('...') 的方式:

const router = new Router({
  routes: [
    {
      path: '/about',
      name: 'About',
      component: () => import('@/components/About.vue')
    }
  ]
});

在 Vue 3 中,同样可以使用这种方式,但也可以结合 defineAsyncComponent 来实现更细粒度的控制:

import { createRouter, createWebHistory } from 'vue - router';
import { defineAsyncComponent } from 'vue';

const About = defineAsyncComponent(() => import('@/components/About.vue'));

const router = createRouter({
  history: createWebHistory(),
  routes: [
    {
      path: '/about',
      name: 'About',
      component: About
    }
  ]
});

export default router;

defineAsyncComponent 可以让我们在异步组件加载时添加加载状态、错误处理等功能。例如:

const About = defineAsyncComponent({
  loader: () => import('@/components/About.vue'),
  loadingComponent: LoadingComponent,
  errorComponent: ErrorComponent,
  delay: 200,
  timeout: 5000
});

这里定义了加载组件 LoadingComponent,错误组件 ErrorComponent,延迟加载时间 delay 为 200 毫秒,超时时间 timeout 为 5000 毫秒。这样在加载 About 组件时,如果超过 5 秒还未加载成功,就会显示 ErrorComponent;在加载过程中,会显示 LoadingComponent

Vue Router 在 Vue 2 和 Vue 3 中的优化

性能优化

  1. 代码分割与懒加载:无论是 Vue 2 还是 Vue 3,路由懒加载都是性能优化的重要手段。通过将组件按需加载,而不是在应用启动时就加载所有组件,可以显著减少初始加载时间。在 Vue 3 中,结合 defineAsyncComponent 可以更好地控制加载过程,提高用户体验。例如,对于一些不常用的页面组件,如用户设置页面、帮助页面等,可以使用懒加载。
  2. 减少不必要的重渲染:在 Vue 组件中,避免在路由变化时进行不必要的重渲染。可以通过 watch 监听 $route 的变化,只在必要时更新组件数据。例如,在一个列表页面,当路由参数变化时,可能只需要重新获取数据,而不需要重新渲染整个列表。
<template>
  <div>
    <ul>
      <li v - for="item in list" :key="item.id">{{ item.name }}</li>
    </ul>
  </div>
</template>

<script>
export default {
  data() {
    return {
      list: []
    };
  },
  watch: {
    $route: {
      immediate: true,
      handler(newRoute) {
        this.fetchData(newRoute.params.category);
      }
    }
  },
  methods: {
    fetchData(category) {
      // 根据 category 获取数据并更新 list
    }
  }
};
</script>

<style>
/* 样式代码 */
</style>

这样,当路由参数变化时,只会触发 fetchData 方法获取新数据,而不会导致整个列表组件的不必要重渲染。

可维护性优化

  1. 模块化路由配置:在 Vue 2 和 Vue 3 中,都应该将路由配置模块化。例如,将不同功能模块的路由分开配置,然后在主路由文件中引入。在一个大型项目中,可能有用户模块、订单模块、商品模块等,每个模块都有自己的路由。
// userRouter.js
import { createRouter, createWebHistory } from 'vue - router';
import UserLogin from '@/components/user/UserLogin.vue';
import UserRegister from '@/components/user/UserRegister.vue';

const userRouter = createRouter({
  history: createWebHistory(),
  routes: [
    {
      path: '/user/login',
      name: 'UserLogin',
      component: UserLogin
    },
    {
      path: '/user/register',
      name: 'UserRegister',
      component: UserRegister
    }
  ]
});

export default userRouter;

// mainRouter.js
import { createRouter, createWebHistory } from 'vue - router';
import Home from '@/components/Home.vue';
import userRouter from './userRouter';

const router = createRouter({
  history: createWebHistory(),
  routes: [
    {
      path: '/',
      name: 'Home',
      component: Home
    },
   ...userRouter.getRoutes()
  ]
});

export default router;

这样,每个模块的路由配置清晰,便于维护和扩展。 2. 合理使用命名路由和命名视图:命名路由可以让我们在代码中更方便地引用路由,特别是在进行编程式导航时。命名视图则可以让我们在一个页面中同时展示多个视图。例如,在一个后台管理页面,可能左侧是菜单视图,右侧是内容视图。

<template>
  <div>
    <router - view name="menu"></router - view>
    <router - view name="content"></router - view>
  </div>
</template>

<script>
export default {
  name: 'Admin'
};
</script>

<style>
/* 样式代码 */
</style>

在路由配置中:

{
  path: '/admin',
  name: 'Admin',
  components: {
    menu: MenuComponent,
    content: ContentComponent
  }
}

这样通过命名视图可以更好地组织页面结构,提高代码的可维护性。

兼容性优化

  1. 处理浏览器兼容性:在使用 Vue Router 时,要考虑不同浏览器的兼容性。例如,在使用 HTML5 历史模式时,有些旧版本浏览器可能不支持。可以通过检测浏览器特性,自动切换到哈希模式。
let history;
if (typeof history.pushState === 'function') {
  history = createWebHistory();
} else {
  history = createWebHashHistory();
}

const router = createRouter({
  history,
  routes: [
    // 路由配置
  ]
});
  1. 与第三方库的兼容性:在项目中可能会使用一些第三方库,要确保 Vue Router 与这些库的兼容性。例如,某些 UI 库可能会对路由切换有特定的要求,需要根据其文档进行配置和调整。

总结与实践建议

通过对 Vue 2 和 Vue 3 中 Vue Router 的功能扩展与优化的探讨,可以看出随着 Vue 版本的升级,Vue Router 也在不断进化,提供了更多强大的功能和更好的性能。

在实际项目中,应根据项目的规模和需求选择合适的功能进行扩展和优化。对于小型项目,可能只需要基本的路由配置和简单的懒加载即可满足需求;而对于大型项目,则需要深入使用导航守卫、路由元信息增强等功能来实现复杂的权限控制和业务逻辑。

同时,要注重性能优化和可维护性,合理使用代码分割、模块化路由配置等技术,让项目在开发和维护过程中更加高效。在兼容性方面,要充分考虑不同浏览器和第三方库的影响,确保项目在各种环境下都能稳定运行。

总之,熟练掌握 Vue Router 的功能扩展与优化技巧,对于构建高质量的 Vue 应用至关重要。希望开发者们在实践中不断探索和总结,充分发挥 Vue Router 的优势,打造出更好的用户体验。