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

一、刚接触Vue Router,咋完成最基础的路由配置?

terry 2小时前 阅读数 5 #Vue

p>做Vue单页应用开发时,Vue Router是管理页面路由的核心工具,但实际写代码时总会碰到各种问题——路由配置报错、跳转不对、页面加载慢…今天用问答形式,把Vue Router开发里常见的坑和解决办法唠明白,从基础到进阶一次讲透~


问题:新建了Vue 3项目,想加路由功能,第一步该干啥?咋把页面和路由对应起来?

回答:先把Vue Router装上,再做三件事:定义路由规则、创建路由实例、把路由挂载到Vue App里。

举个实际步骤:

  1. 安装依赖:打开终端,执行npm install vue-router@4(Vue 3对应Vue Router 4,Vue 2对应v3版本,得注意版本匹配)。
  2. 新建路由文件:在src目录下建个router/index.js,里面写路由规则,比如有Home和About两个页面:
    import { createRouter, createWebHistory } from 'vue-router'
    // 导入页面组件(也可以用懒加载,后面讲)
    import HomeView from '../views/HomeView.vue'
    import AboutView from '../views/AboutView.vue'

const routes = [ { path: '/', // 访问根路径时 name: 'home', component: HomeView // 渲染HomeView组件 }, { path: '/about', name: 'about', component: AboutView } ]

const router = createRouter({ history: createWebHistory(), // 用HTML5的history模式,URL没有# routes // 上面定义的路由规则数组 })

export default router

**挂载到Vue App**:打开`src/main.js`,把路由实例注入Vue:  
```javascript
import { createApp } from 'vue'
import App from './App.vue'
import router from './router' // 引入上面写的路由文件
const app = createApp(App)
app.use(router) // 注册路由插件
app.mount('#app')
  1. 添加路由出口:最后在App.vue里加<router-view>,这个标签是路由组件的“容器”,访问不同路径时,对应的组件会渲染到这里:
    <template>
    <div>
     <!-- 路由出口,渲染匹配的组件 -->
     <router-view></router-view>
    </div>
    </template>

这样基础路由就跑通了~要是页面没渲染,先检查路径、组件导入、<router-view>有没有漏加这几个点。

页面跳转有声明式和编程式,该咋选?带参数咋传?

问题1:点击按钮跳转到About页面,用<router-link>还是写JS逻辑?两者有啥区别?

回答:这俩都是跳转路由的方式,场景不同:

  • 声明式(<router-link>:适合在模板里直接写导航,比如导航栏、菜单这些UI元素,它本质是个a标签,但做了优化(比如自动添加激活样式),用法:

    <template>
    <router-link to="/about">去About页面</router-link>
    </template>

    还能通过to传对象,控制命名路由和参数:

    <router-link :to="{ name: 'about', query: { tab: 'info' } }">去About并带参数</router-link>
  • 编程式(router.push:适合在JS逻辑里跳转,比如点击按钮后要做判断再跳转,先在组件里导入useRouter(Vue 3组合式API),再调用push:

    <script setup>
    import { useRouter } from 'vue-router'
    const router = useRouter()

const goAbout = () => { router.push('/about') // 直接传路径 // 或者传对象(和router-link的to对象格式一样) router.push({ name: 'about', query: { tab: 'info' } }) }

```

简单说,UI上的导航用声明式,逻辑里的跳转用编程式,灵活度更高~

问题2:跳转时要带参数,动态路由(/user/:id)和查询参数(?id=1)有啥区别?咋取参数?

回答:两种传参方式适用场景不一样:

  • 动态路由(路径参数):适合参数是URL的一部分,比如用户详情页/user/123,参数变化时页面是同一个(只是数据变),配置路由时要写:参数名

    // 路由规则里定义
    {
    path: '/user/:id', 
    name: 'user',
    component: UserView
    }

    跳转时传参数(以编程式为例):

    router.push('/user/123') // 或者对象形式 { name: 'user', params: { id: 123 } }

    组件里取参数(Vue 3组合式API):

    <script setup>
    import { useRoute } from 'vue-router'
    const route = useRoute()
    console.log(route.params.id) // 拿到123
    </script>
  • 查询参数(query):适合参数不是URL核心部分,比如搜索页/search?keyword=vue,参数可传可不传,刷新页面参数还在,配置路由时不用改path,直接在跳转时加query:

    router.push({ path: '/search', query: { keyword: 'vue' } })

    组件里取参数:

    <script setup>
    import { useRoute } from 'vue-router'
    const route = useRoute()
    console.log(route.query.keyword) // 拿到vue
    </script>

动态路由参数是URL的“固定部分”,适合标识资源;query参数是“附加信息”,适合筛选、搜索这类场景~

路由守卫咋用?权限控制、改页面标题这些需求咋实现?

问题1:进入页面之前要判断用户是否登录,没登录就跳登录页,咋用路由守卫做权限控制?

回答:路由守卫能在“导航过程中”插一脚,做权限判断、加载数据这些事,最常用的是全局前置守卫beforeEach,在路由实例里配置:

打开router/index.js,在创建router之后加:

router.beforeEach((to, from, next) => {
  // to:要去的目标路由;from:从哪个路由来;next:放行/跳转的函数
  const isLogin = localStorage.getItem('token') // 假设用localStorage存token
  if (to.name !== 'login' && !isLogin) { 
    // 不是登录页,且没登录 → 跳登录页
    next({ name: 'login' })
  } else {
    // 已登录,或者要去的是登录页 → 放行
    next()
  }
})

这样,每次路由跳转前都会触发这个守卫,判断登录状态,注意:Vue Router 4里,next可以返回一个路由对象,也可以直接调用next()放行,如果用TypeScript,要注意类型定义~

组件内守卫(比如beforeRouteEnter)适合组件内部的逻辑,但Vue 3组合式API里,组件内守卫改成用onBeforeRouteEnter这些钩子了(需要导入):

<script setup>
import { onBeforeRouteEnter } from 'vue-router'
onBeforeRouteEnter((to, from) => {
  // 进入组件前触发,这里还拿不到this(组件实例没创建)
  console.log('准备进入这个组件啦')
})
</script>

根据项目复杂度选全局或组件内守卫,权限控制一般用全局守卫更方便~

问题2:想在每个页面跳转后,把页面标题改成路由对应的名字,咋做?

回答:还是用全局前置守卫beforeEach,因为导航完成后页面标题要变,所以可以在beforeEach里处理:

router.beforeEach((to, from) => {
  // 假设路由规则里给每个路由配了meta.title
  document.title = to.meta.title || '默认标题'
  // 记得放行
  return true 
  // 或者用next(),不过Vue Router 4里return true和next()效果一样,更推荐return
})
// 路由规则里加meta
const routes = [
  {
    path: '/',
    name: 'home',
    component: HomeView,
    meta: { title: '首页' } // 自定义元信息
  },
  {
    path: '/about',
    name: 'about',
    component: AboutView,
    meta: { title: '关于我们' }
  }
]

这样每次跳转路由时,页面标题就会自动变成meta.title的值,用户体验更友好~

后台管理系统有嵌套布局,嵌套路由咋配置?

问题:做后台系统时,顶部有导航栏、左侧有侧边栏,内容区是不同页面,这种嵌套结构咋用Vue Router实现?

回答:用嵌套路由(children),把父组件当“布局容器”,子路由渲染到父组件的<router-view>里。

步骤示例:

  1. 建布局组件:先建布局组件LayoutView.vue,里面包含侧边栏、顶部栏,还有一个<router-view>给子路由:

    <template>
    <div class="layout">
     <aside>侧边栏</aside>
     <main>
       <router-view></router-view> <!-- 子路由渲染到这里 -->
     </main>
    </div>
    </template>
  2. 配置路由规则:给父路由加children数组:

    const routes = [
    {
     path: '/dashboard',
     name: 'dashboard',
     component: LayoutView, // 父组件(布局)
     children: [
       {
         path: '', // 子路由的默认路径,访问/dashboard时渲染
         name: 'dashboard-home',
         component: DashboardHomeView
       },
       {
         path: 'users', // 访问/dashboard/users时渲染
         name: 'dashboard-users',
         component: DashboardUsersView
       },
       {
         path: 'posts', // 访问/dashboard/posts时渲染
         name: 'dashboard-posts',
         component: DashboardPostsView
       }
     ]
    }
    ]
  3. 效果验证:当用户访问/dashboard时,LayoutView渲染,同时子路由dashboard-home的组件也渲染到LayoutView的<router-view>里;访问/dashboard/users时,子路由dashboard-users的组件渲染。

嵌套路由的关键是父路由组件里必须有<router-view>,用来放子路由的内容,这种方式特别适合多布局的项目,比如前台和后台用不同的父布局~

路由太多导致首屏加载慢,咋做懒加载优化?

问题:项目里页面越来越多,打包后JS文件特别大,首屏要等好久,咋让路由组件按需加载?

回答:用路由懒加载,借助webpack的代码分割功能,让每个路由组件单独打包,访问时再加载,减少首屏压力。

做法很简单:把路由规则里的component从“静态导入”改成“动态导入”(用import()语法)。

原来的静态导入:

import HomeView from '../views/HomeView.vue'
// 路由规则里用HomeView

改成懒加载后:

const HomeView = () => import('../views/HomeView.vue')
// 路由规则里还是用HomeView

或者直接在路由规则里写:

const routes = [
  {
    path: '/',
    name: 'home',
    component: () => import('../views/HomeView.vue') // 动态导入
  },
  // 其他路由同理
]

这样打包时,每个路由组件会被拆成单独的chunk,只有当用户访问对应路由时,才会加载这个chunk,首屏加载的JS体积就小了很多。

如果想给懒加载加loading状态(比如加载时显示loading组件),可以用import()的.then和.catch:

component: () => import('../views/HomeView.vue').then(module => module.default).catch(err => {
  // 加载失败时,返回一个默认组件(比如ErrorView)
  return import('../views/ErrorView.vue')
})

懒加载是性能优化的基础操作,项目大了一定要安排上~

路由报错和404页面咋处理?

问题1:用户输入不存在的路由(比如/xxx),咋跳转到404页面?

回答:用*通配符路由(``)**,把它放在路由规则的最后(因为路由匹配是从上到下的,通配符要兜底):

const routes = [
  // 其他路由规则...
  {
    path: '/:pathMatch(.*)*', // Vue Router 4里用这个格式匹配所有路径
    name: 'not-found',
    component: NotFoundView // 自己写的404组件
  }
]

这样,只要用户访问的路径没被前面的路由匹配到,就会跳转到NotFoundView,注意路径匹配的语法:Vue Router 3是,Vue Router 4要写成/:pathMatch(.*)*才能正确匹配所有层级(比如/a/b/c这种多级路径)。

问题2:路由跳转时控制台报NavigationDuplicated错误,咋解决?

回答:这个错误是因为“重复跳转到当前路由”导致的(比如点击同一个导航按钮多次),Vue Router 4里可以这样处理:

封装router.push,捕获错误(适合编程式跳转):

// 在router/index.js里封装
const originalPush = router.push
router.push = function push(location, onComplete, onAbort) {
  return originalPush.call(this, location, onComplete, onAbort).catch(err => {
    if (err.name !== 'NavigationDuplicated') {
      return Promise.reject(err)
    }
  })
}

router.replace代替router.push,因为replace不会留下历史记录,重复点击时不会触发重复导航(适合不需要回退的场景,比如登录按钮):

router.replace('/login') // 代替router.push

在模板里的<router-link>replace属性,让跳转变成replace模式:

<router-link to="/login" replace>去登录</router-link>

选一种适合项目的方式就行,一般封装router.push能一劳永逸解决重复跳转的问题~

最后唠叨两句

Vue Router的知识点不算少,但核心就是路由配置、跳转、守卫、嵌套、优化、错误处理这几块,实际开发中,先把基础流程走通,再逐步处理权限、性能、异常这些细节,遇到问题时,先看官方文档(Vue Router的文档写得很详细,还有示例),再结合场景调试。

要是刚开始学,建议把每个知识点拆成小demo练手——比如先写基础路由,再加个带参数的跳转,然后用守卫做权限,最后用懒加载优化,练一遍下来,对路由的理解就扎实多啦~

(文章到这里差不多覆盖了Vue Router开发中80%的常见问题,从基础到进阶,每个环节都结合了实际场景和代码示例,新手跟着做能少踩很多坑~)

版权声明

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

发表评论:

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

热门