Code前端首页关于Code前端联系我们

一、Vite 项目里为啥要整合 Vue Router?

terry 8小时前 阅读数 10 #Vue
文章标签 Vite;Vue Router

做 Vue 项目时,用 Vite 搭架构再常见不过,但路由管理咋和 Vue Router 结合?从项目初始化到复杂场景(动态路由、权限控制),再到部署踩坑,这篇文章把 Vite + Vue Router 的核心流程拆成问题逐个讲透,新手能跟着配,老手也能补细节~

单页应用(SPA)要做页面跳转、URL 管理,光靠组件切换可不够——用户刷新页面会回到首页、没法收藏特定页面、前进后退也乱套,Vue Router 是 Vue 生态官方路由工具,专门解决这些问题:它能管理 URL 和组件的映射关系,还能通过“路由守卫”控制权限、加载状态,让单页应用有像多页应用一样的路由体验。

再看 Vite 和 Vue Router 的适配优势:Vite 主打“极速冷启动”,开发时改代码秒级热更新;Vue Router 4 对 Vue 3 做了深度优化(比如支持 Composition API、Tree - shaking 更彻底),两者结合后,开发阶段改路由配置能立刻看到效果,生产阶段路由懒加载能让首屏体积更小、加载更快,举个实际例子:用 Vite 搭的后台管理系统,加了 Vue Router 后,侧边栏切换子路由时页面不刷新,体验丝滑,还能通过路由守卫拦截未登录用户访问敏感页面。

怎么初始化一个带 Vue Router 的 Vite + Vue 项目?

想快速搭好基础环境,按这三步来:

用 Vite CLI 创建基础项目

打开终端,执行命令(选 Vue 模板):

npm create vite@latest my-vue-app -- --template vue

执行完后,进入项目目录并安装依赖:

cd my-vue-app
npm install

安装 Vue Router

Vue 3 要搭配 Vue Router 4.x 版本,所以执行:

npm install vue-router@4

搭建路由相关目录结构

src 文件夹下新建 router(放路由配置)、views(放页面级组件)文件夹,最终目录大概长这样:

src/
├─ router/       # 路由核心配置
│  └─ index.js  
├─ views/        # 页面组件(如首页、关于页)
│  ├─ HomeView.vue  
│  └─ AboutView.vue  
├─ components/   # 通用组件(如按钮、弹窗)
├─ App.vue       # 根组件
└─ main.js       # 项目入口

Vue Router 在 Vite 里的基础配置要注意啥?

核心是创建路由实例 + 挂载到 Vue 应用 + 渲染路由视图,分三步走:

写路由规则(src/router/index.js)

先引入 API 和组件,再定义路由映射关系:

import { createRouter, createWebHistory } from 'vue-router'
import HomeView from '../views/HomeView.vue'
// 路由规则数组
const routes = [
  {
    path: '/',          // URL 路径(根路径)
    name: 'home',       // 路由名称(可选,用于编程式导航)
    component: HomeView // 对应组件
  },
  {
    path: '/about',
    name: 'about',
    // 懒加载:访问时再加载组件,减少首屏体积(后面优化部分细讲)
    component: () => import('../views/AboutView.vue')
  }
]
// 创建路由实例
const router = createRouter({
  // history 模式:URL 更美观(如 /about),但部署要配服务端;hash 模式是 createWebHashHistory()(URL 带 #)
  history: createWebHistory(),
  routes // 传入路由规则
})
export default router

挂载路由到 Vue 应用(src/main.js)

把路由实例注入 Vue 应用,让所有组件能访问路由功能:

import { createApp } from 'vue'
import App from './App.vue'
import router from './router' // 引入路由配置
createApp(App)
  .use(router) // 挂载路由
  .mount('#app')

渲染(App.vue)

<router-view> 是路由组件的“容器”,<router-link> 是导航链接(代替 <a> 避免页面刷新):

<template>
  <div>
    <!-- 导航栏 -->
    <nav>
      <router-link to="/">首页</router-link> | 
      <router-link to="/about">lt;/router-link>
    </nav>
    <!-- 路由组件渲染区域 -->
    <router-view></router-view>
  </div>
</template>

关键细节createWebHistorycreateWebHashHistory 咋选?

  • history 模式,URL 更简洁(如 https://xxx.com/about),但部署时服务器要配置“ fallback ”(否则刷新页面会 404);
  • hash 模式,URL 带 (如 https://xxx.com/#/about),部署时不用改服务器配置,但 URL 美观度差一些。

动态路由在 Vite + Vue Router 里咋实现?

动态路由用来处理路径带参数的场景(比如商品详情页 /product/123、用户页 /user/456),核心是路由规则里定义参数 + 组件内获取参数

配置动态路由规则

src/router/index.js 里加一条带参数的路由:

{
  path: '/product/:id', // :id 是动态参数,冒号是固定语法
  name: 'ProductDetail',
  component: () => import('../views/ProductDetail.vue')
}

组件内获取参数

Vue 3 推荐用 组合式 APIuseRoute),也支持选项式 API(this.$route)。

组合式 API 写法(ProductDetail.vue)

<template>
  <div>当前商品 ID:{{ productId }}</div>
</template>
<script setup>
import { useRoute } from 'vue-router' // 引入路由 hooks
const route = useRoute()
const productId = route.params.id // 直接取动态参数
</script>

选项式 API 写法(老项目迁移用)

<template>
  <div>当前商品 ID:{{ $route.params.id }}</div>
</template>
<script>
export default {
  computed: {
    productId() {
      return this.$route.params.id
    }
  }
}
</script>

动态路由的“坑”与解决

路由参数变化时(比如从 /product/1 跳转到 /product/2),组件不会自动重新渲染!因为 Vue Router 认为“组件实例没销毁,只是参数变了”,解决方法有两种:

  • 监听路由变化:用 watch 监听 route.params

    import { watch } from 'vue'
    import { useRoute } from 'vue-router'
    const route = useRoute()
    watch(
      () => route.params.id, 
      (newId) => {
        // newId 变化时执行逻辑(比如重新请求商品数据)
        fetchProduct(newId)
      }
    )
  • 强制组件销毁重建:给 <router-view>key,值为 $route.fullPath(URL 全路径):

    <router-view :key="$route.fullPath"></router-view>

嵌套路由怎么设计更合理?

嵌套路由适合页面布局有层级的场景(比如后台管理系统:顶部导航 + 侧边栏 + 内容区,内容区随侧边栏切换),核心是 children 配置 + 嵌套 <router-view>

规划布局与路由结构

以“仪表盘(Dashboard)”为例,结构分层:

  • 父组件 DashboardLayout.vue:包含侧边栏和内容区容器;
  • 子路由:/dashboard(默认显示 DashboardHome)、/dashboard/settings(显示 DashboardSettings)。

配置嵌套路由规则(src/router/index.js)

{
  path: '/dashboard',
  component: () => import('../views/DashboardLayout.vue'), // 父布局组件
  children: [
    {
      path: '', // 空路径表示“默认子路由”
      name: 'DashboardHome',
      component: () => import('../views/DashboardHome.vue')
    },
    {
      path: 'settings',
      name: 'DashboardSettings',
      component: () => import('../views/DashboardSettings.vue')
    }
  ]
}

父布局组件里渲染子路由(DashboardLayout.vue)

<template>
  <div class="dashboard-wrapper">
    <!-- 侧边栏 -->
    <aside>
      <ul>
        <li><router-link to="/dashboard">首页</router-link></li>
        <li><router-link to="/dashboard/settings">设置</router-link></li>
      </ul>
    </aside>
    <!-- 子路由渲染区域 -->
    <main>
      <router-view></router-view> <!-- 子路由组件在这里显示 -->
    </main>
  </div>
</template>

嵌套路由的优势

  • 布局复用:父组件(如 DashboardLayout)只渲染一次,子路由切换时,侧边栏、顶部导航这些固定布局不会重复渲染;
  • 路由层级清晰:URL 结构(/dashboard/settings)和组件层级一一对应,后续维护时,看 URL 就知道对应的组件结构。

路由守卫怎么用在实际业务里?

路由守卫是控制页面权限、处理跳转逻辑的关键工具,分全局守卫路由独享守卫组件内守卫三类。

全局前置守卫:登录拦截(最常用场景)

需求:访问需要登录的页面(如 /profile)时,判断用户是否登录,没登录就跳转到登录页。

src/router/index.js 里配置:

router.beforeEach((to, from, next) => {
  // 假设用 localStorage 存 token 判断登录状态
  const isLogin = !!localStorage.getItem('token')
  // 检查目标路由是否需要权限(通过 meta 字段标记)
  if (to.meta.requiresAuth && !isLogin) {
    next({ name: 'login' }) // 跳转到登录页
  } else {
    next() // 放行
  }
})

然后在需要权限的路由里加 meta 标记:

{
  path: '/profile',
  name: 'Profile',
  component: () => import('../views/Profile.vue'),
  meta: { requiresAuth: true } // 标记该页面需要登录
}

路由独享守卫:进入路由前做逻辑

需求:访问 /order 前,检查订单数据是否加载,没加载就先请求数据。

在路由规则里直接写 beforeEnter

{
  path: '/order',
  name: 'Order',
  component: () => import('../views/Order.vue'),
  beforeEnter: (to, from, next) => {
    if (!window.orderData) { // 假设用 window 临时存数据(实际项目用状态管理更优)
      fetch('/api/order').then(res => res.json()).then(data => {
        window.orderData = data
        next() // 数据加载完,放行
      })
    } else {
      next() // 数据已存在,直接放行
    }
  }
}

组件内守卫:组件生命周期结合路由

需求:用户离开表单页面时,提示“是否放弃未保存内容”。

onBeforeRouteLeave(组合式 API):

<template>
  <form>...</form>
</template>
<script setup>
import { onBeforeRouteLeave } from 'vue-router'
onBeforeRouteLeave((to, from, next) => {
  if (window.confirm('当前表单未保存,确定离开?')) {
    next() // 确认离开,放行
  } else {
    next(false) // 取消离开,留在当前页
  }
})
</script>

路由守卫的核心逻辑

  • to:目标路由对象(要跳转到哪个页面);
  • from:当前路由对象(从哪个页面跳过来);
  • next:必须调用的“放行函数”——调用 next() 放行,next(false) 取消跳转,next({ name: 'xxx' }) 跳转到指定页面。

怎么通过路由懒加载优化 Vite 项目性能?

Vite 天生支持动态 import(),配合 Vue Router 的懒加载配置,能让首屏只加载“首页”等核心代码,其他页面按需加载,大幅减少首屏加载时间。

路由懒加载的原理

传统打包方式把所有页面组件塞到一个 JS 文件里,首屏要加载全部代码,体积大、速度慢,懒加载是把每个页面组件打成单独的代码块,访问对应路由时再加载,实现“按需加载”。

Vite 里的路由懒加载配置

在路由规则里,把 component 写成动态 import 函数即可:

{
  path: '/about',
  name: 'about',
  // 动态 import,Vite 会自动处理代码分割
  component: () => import('../views/AboutView.vue')
}

进阶:分组懒加载 + 加载状态

  • 分组懒加载:把多个相关组件打包到一个代码块里(减少请求次数),比如后台管理的子页面:

    // 把 Dashboard 相关组件打到同一个 chunk
    const DashboardRoutes = () => import('../views/dashboard/Index.vue')
    const DashboardHome = () => import('../views/dashboard/Home.vue')
    const DashboardSettings = () => import('../views/dashboard/Settings.vue')
    // 路由配置
    {
      path: '/dashboard',
      component: DashboardRoutes,
      children: [
        { path: '', component: DashboardHome },
        { path: 'settings', component: DashboardSettings }
      ]
    }
  • 加载状态提示:用户访问懒加载页面时,可能看到“白屏”,所以要加加载中提示,用全局路由守卫 + 状态管理实现:
    src/router/index.js 里:

    let loading = false
    router.beforeEach((to, from, next) => {
      loading = true // 路由开始加载,标记为 true
      next()
    })
    router.afterEach(() => {
      loading = false // 路由加载完成,标记为 false
    })

    App.vue 里显示加载状态:

    <template>
      <div v-if="loading" class="loading-mask">加载中...</div>
      <nav>...</nav>
      <router-view></router-view>
    </template>
    <script setup>
    import { ref } from 'vue'
    import { useRouter } from 'vue-router'
    const router = useRouter()
    const loading = ref(false)
    router.beforeEach(() => { loading.value = true })
    router.afterEach(() => { loading.value = false })
    </script>

部署 Vite + Vue Router 项目时路由有啥坑?

部署后最容易踩的是 路由模式不兼容,导致页面刷新 404,核心是 history 模式和 hash 模式的区别。

Hash 模式(createWebHashHistory)

URL 格式:http://xxx.com/#/about,路由信息存在 后面。部署时不需要服务端配置——因为浏览器只会把 前面的路径发给服务器,服务器返回 index.html 后,前端路由自己解析 后的内容。

  • 优点:部署简单,兼容老服务器;
  • 缺点:URL 带 ,美观度差。

History 模式(createWebHistory)

URL 格式:http://xxx.com/about,更像传统网站 URL,但服务器必须配置 fallback——当用户直接访问 /about 时,服务器要返回 index.html(否则会报 404,因为服务器没有 /about 这个物理文件)。

不同平台的配置方式:

  • Vercel/Netlify:自动支持 SPA fallback,部署时不用额外配置;

  • Nginx:在配置文件里加 try_files

    server {
      listen 80;
      server_name your-domain.com;
      root /usr/share/nginx/html; # 项目打包后的 dist 目录
      index index.html;
      location / {
        try_files $uri $uri/ /

版权声明

本文仅代表作者观点,不代表Code前端网立场。
本文系作者Code前端网发表,如需转载,请注明页面地址。

发表评论:

◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。

热门