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

Vue Router 核心是解决啥问题的?

terry 6小时前 阅读数 9 #Vue

p>咱做Vue项目的时候,经常需要在不同页面之间跳转,还得让URL和页面状态对应上,这时候Vue Router就派上大用场了!它是Vue.js官方的路由管理器,专门解决单页应用(SPA)里的页面导航、组件切换这些问题,不管是做个人博客、电商网站还是后台管理系统,搞懂Vue Router能让页面跳转丝滑又省心,接下来咱从基础到实战,把Vue Router的关键知识点和项目里的用法唠明白~

先想明白单页应用(SPA)的特点:整个项目就一个HTML页面,页面切换靠JS动态渲染组件,要是没有路由管理,用户刷新页面就回到初始状态,而且URL也不变,根本分不清当前在哪个“页面”,Vue Router干的事儿就是让URL和组件一一对应,比如访问 /home 显示首页组件,访问 /about 显示关于页组件;同时支持无刷新跳转,还能管理路由参数、页面状态。

举个实际场景:做电商APP的商品列表页,点某个商品跳转到详情页,URL变成 /product/123(123是商品ID),这时候Vue Router能帮咱把商品ID从URL里取出来,传给详情组件,还能在用户刷新页面时,让详情页依然显示对应商品信息,要是没有路由,要么页面切换卡成PPT,要么刷新就“失忆”,体验拉胯~

想在Vue项目里用Vue Router,得咋起步?

#### 1. 先把Vue Router装到项目里 Vue2和Vue3对应的Vue Router版本不一样: - Vue2项目 → 装 vue-router@3(命令:npm i vue-router@3) - Vue3项目 → 装 vue-router@4(命令:npm i vue-router@4

装完后,得在项目里配置路由实例。

配置路由规则(以Vue3 + Vue Router4为例)

新建个 router/index.js 文件,基本结构长这样:

import { createRouter, createWebHistory } from 'vue-router'
// 引入页面组件
import HomeView from '../views/HomeView.vue'
import AboutView from '../views/AboutView.vue'
const router = createRouter({
  history: createWebHistory(), // 路由模式:history模式(URL没有#)
  routes: [ // 路由规则数组
    {
      path: '/', // 访问根路径
      name: 'home',
      component: HomeView // 对应组件
    },
    {
      path: '/about',
      name: 'about',
      component: AboutView
    }
  ]
})
export default router

然后在 main.js 里把路由挂载到Vue应用:

import { createApp } from 'vue'
import App from './App.vue'
import router from './router' // 引入路由实例
const app = createApp(App)
app.use(router) // 注入路由
app.mount('#app')

让路由“显示”在页面里

在根组件(App.vue)里,用 <router-view> 标签当“容器”,路由匹配到的组件会渲染到这里:

<template>
  <div id="app">
    <!-- 导航链接 -->
    <router-link to="/">首页</router-link>
    <router-link to="/about">lt;/router-link>
    <!-- 路由组件渲染的地方 -->
    <router-view></router-view>
  </div>
</template>

<router-link> 是Vue Router提供的导航组件,点击后会触发路由跳转,比自己写 <a> 标签+window.location 优雅多了,还能避免页面刷新~

项目里常见的路由玩法有哪些?

#### 1. 动态路由:页面根据URL参数变化 比如做用户中心,每个用户的详情页URL是 /user/1/user/2… 这里的 12 是用户ID,属于**动态参数**,配置路由时,用 :参数名 标记动态段: ```js routes: [ { path: '/user/:id', // :id 是动态参数 name: 'user', component: UserView } ] ``` 在 UserView 组件里,通过 useRoute(Vue3组合式API)或者 this.$route(Vue2选项式API)拿到参数: ```js // Vue3 组合式API import { useRoute } from 'vue-router' export default { setup() { const route = useRoute() console.log(route.params.id) // 拿到URL里的id } }

// Vue2 选项式API export default { mounted() { console.log(this.$route.params.id) } }

场景超常见:电商商品详情、论坛帖子详情、个人主页都得这么玩~  
#### 2. 嵌套路由:页面里再套页面  
比如后台管理系统, layouts 有侧边栏(SideBar)和主体内容(MainContent),点击侧边栏菜单,主体内容区切换不同页面,这就是**嵌套路由**,配置时用 <code>children</code> 数组:  
```js
routes: [
  {
    path: '/admin',
    component: AdminLayout, // 父布局组件
    children: [
      {
        path: 'dashboard', // 注意:子路由path不加/,最终URL是 /admin/dashboard
        component: DashboardView
      },
      {
        path: 'settings',
        component: SettingsView
      }
    ]
  }
]

父组件 AdminLayout.vue 里得有 <router-view> 来渲染子路由组件:

<template>
  <div class="admin-layout">
    <SideBar /> <!-- 侧边栏组件 -->
    <router-view></router-view> <!-- 子路由组件渲染到这 -->
  </div>
</template>

这样结构清晰,还能复用布局,后台系统、博客后台这类有层级的页面都靠嵌套路由组织~

路由懒加载:让首屏加载更快

如果项目页面多,把所有组件都打包到一个JS文件里,首屏加载会很慢。路由懒加载就是让组件在需要的时候再加载(比如用户访问到某个路由时才加载对应的组件),配置时把 component 改成函数式导入:

routes: [
  {
    path: '/about',
    component: () => import('../views/AboutView.vue') // 懒加载,访问/about时才加载组件
  }
]

这样打包后,每个路由组件会生成单独的JS块,首屏只加载必要的代码,用户等的时间更短,体验更爽~

编程式导航:用JS控制跳转

除了 <router-link> 点击跳转,有时候需要在代码里触发跳转(比如登录成功后跳转到首页),这时候用编程式导航,Vue Router提供了 router.pushrouter.replace 这些方法:

// Vue3 组合式API(先引入useRouter)
import { useRouter } from 'vue-router'
export default {
  setup() {
    const router = useRouter()
    const handleLogin = () => {
      // 登录逻辑...
      router.push('/home') // 跳转到首页
    }
    return { handleLogin }
  }
}
// Vue2 选项式API
export default {
  methods: {
    handleLogin() {
      // 登录逻辑...
      this.$router.push('/home')
    }
  }
}

router.push 会往历史记录里添加新记录,router.replace 是替换当前记录(比如支付成功后替换成结果页,用户返回不会回到支付页),router.go(1) 类似浏览器的前进,router.go(-1) 是后退~

路由守卫是干啥的?项目里咋用?

路由守卫就像“门卫”,在路由跳转的**前、中、后**插手,做权限判断、加载数据、修改页面标题这些事儿。

全局守卫:控制所有路由跳转

最常用的是 router.beforeEach,每次路由跳转前都会触发,比如后台系统,进入 /admin 前检查用户是否登录:

// router/index.js 里配置
router.beforeEach((to, from, next) => {
  const isLogin = localStorage.getItem('token') // 假设用token判断登录
  if (to.path.startsWith('/admin') && !isLogin) {
    next('/login') // 没登录,跳转到登录页
  } else {
    next() // 放行
  }
})

to 是要跳转到的目标路由,from 是当前离开的路由,next 是必须调用的函数(放行、跳转、取消都靠它)。

路由独享守卫:只管单个路由

在路由配置里写 beforeEnter,比如某个敏感页面,除了全局权限,还要额外校验:

routes: [
  {
    path: '/secret',
    component: SecretView,
    beforeEnter: (to, from, next) => {
      const hasPermission = checkPermission() // 自定义权限检查函数
      if (hasPermission) {
        next()
      } else {
        next('/403') // 没权限跳403页面
      }
    }
  }
]

组件内守卫:组件自己管自己

在组件里写 beforeRouteEnter(进入前)、beforeRouteUpdate(路由参数变化但组件复用)、beforeRouteLeave(离开前),比如编辑表单页面,离开前提醒用户保存:

// Vue2 选项式API
export default {
  beforeRouteLeave(to, from, next) {
    if (this.formEdited) { // 假设formEdited标记表单是否修改
      const confirm = window.confirm('表单没保存,确定离开吗?')
      if (confirm) {
        next()
      } else {
        next(false) // 取消跳转
      }
    } else {
      next()
    }
  }
}
// Vue3 组合式API(用onBeforeRouteLeave)
import { onBeforeRouteLeave } from 'vue-router'
export default {
  setup() {
    onBeforeRouteLeave((to, from, next) => {
      // 逻辑和上面类似
      next()
    })
  }
}

组件内守卫很灵活,适合处理组件自身的状态和逻辑~

遇到路由相关的 bug,咋排查?

项目里路由出问题,常见场景和解决方法总结几个典型的:

404页面不生效

想配个404页面,结果访问不存在的路由还是白屏?原因:路由配置的顺序不对,404的路由得放在最后(因为路由匹配是从上到下,一旦前面匹配到就不会往后走),正确配置:

routes: [
  { path: '/home', component: HomeView },
  { path: '/about', component: AboutView },
  // 其他路由...
  { path: '/:pathMatch(.*)*', component: Error404View } // 匹配所有未定义的路由
]

刷新页面后路由“崩了”(history模式)

createWebHistory(Vue3)或 mode: 'history'(Vue2)时,刷新页面报404?原因:history模式下,URL没有,后端不知道 /user/123 对应的是前端路由,所以返回404。解决:让后端配置“所有请求都返回index.html”,把路由控制权交回前端,比如Nginx配置:

location / {
  try_files $uri $uri/ /index.html;
}

路由参数变了,组件没更新

比如从 /user/1 跳转到 /user/2,组件还是显示用户1的信息?原因:Vue Router发现组件是同一个,不会重新渲染,所以数据没更新。解决

  • watch 监听路由参数变化:
    // Vue3 组合式API
    import { watch, useRoute } from 'vue-router'
    setup() {
      const route = useRoute()
      watch(() => route.params.id, (newId) => {
        // 根据newId重新请求数据
      })
    }
  • 用组件内守卫 beforeRouteUpdate
    // Vue2 选项式API
    beforeRouteUpdate(to, from, next) {
      this.fetchData(to.params.id) // 重新请求数据
      next()
    }

嵌套路由不显示子组件

配置了children路由,但子组件就是不渲染?原因:父组件里没放 <router-view>,子路由不知道该渲染到哪。解决:在父组件模板里加上 <router-view>AdminLayout.vue 必须有这个标签才能显示子路由组件~

Vue2和Vue3的Vue Router有啥不一样?

很多同学升级Vue3后,发现路由配置报错,因为Vue Router v4(对应Vue3)和v3(对应Vue2)变化挺大:

路由创建方式

  • Vue2 + vue-router@3:

    import Vue from 'vue'
    import VueRouter from 'vue-router'
    Vue.use(VueRouter)
    const router = new VueRouter({
      mode: 'history',
      routes: [...]
    })
  • Vue3 + vue-router@4:

    import { createRouter, createWebHistory } from 'vue-router'
    const router = createRouter({
      history: createWebHistory(), // 代替mode: 'history'
      routes: [...]
    })
    // 不需要Vue.use,直接app.use(router)

组合式API的支持

Vue3里可以用 useRouteruseRoute 在setup里获取路由实例和当前路由:

import { useRouter, useRoute } from 'vue-router'
export default {
  setup() {
    const router = useRouter()
    const route = useRoute()
    // 不用this,更简洁
  }
}

导航失败的处理

Vue3中,router.push 返回的是Promise,如果导航被取消(比如重复跳转同一个路由),会抛出错误,可以用 try...catch 捕获:

const router = useRouter()
async function goToPage() {
  try {
    await router.push('/same-page')
  } catch (error) {
    if (isNavigationFailure(error, NavigationFailureType.aborted)) {
      // 导航被取消,做提示
    }
  }
}

路由实例的挂载

Vue2是在Vue构造函数上挂载路由,Vue3是通过 app.use(router) 挂载到应用实例,更贴合组合式API的设计~

Vue Router是Vue项目里管理页面导航的核心工具,从基础配置到动态路由、嵌套路由、守卫这些进阶玩法,再到版本差异和bug排查,把这些搞透了,做SPA项目就更顺手,实际项目里多练,比如搭个小后台系统,用嵌套路由组织布局,用动态路由做用户管理,用路由守卫做权限控制,很快就能掌握精髓~

版权声明

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

发表评论:

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

热门