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

Vue Router的该怎么用?常见问题全解答

terry 18小时前 阅读数 12 #Vue
文章标签 Vue Router常见问题

刚接触Vue Router的同学,肯定对既好奇又有点懵——它和普通a标签有啥不一样?怎么用它实现页面跳转、传参?激活样式咋设置?别慌,这篇文章把从基础到进阶的常见问题掰开揉碎讲清楚,帮你彻底搞懂这个Vue路由里的核心组件~

基础用法:怎么实现页面跳转?

Vue Router里的是专门用来做“单页应用内跳转”的组件,替代了传统的标签,它的核心作用是在不刷新整个页面的前提下,实现视图切换(因为SPA应用靠路由控制不同组件显示,不是真的跳转到新页面)。

最基础的用法是通过to属性指定目标路径:

  • 字符串路径:直接写要跳转的路由地址,比如跳转到首页:
    <router-link to="/home">首页</router-link>
  • 对象形式:当需要传参、指定路由名称时更灵活,比如路由配置里给某个页面起了name(如name: 'User'),可以这样写:
    <router-link :to="{ name: 'User', params: { id: 123 }, query: { tab: 'info' } }">用户页</router-link>

    这里name对应路由的名称,params传动态参数,query传查询参数。

以前版本里还能通过tag属性指定渲染成什么HTML标签(比如button、div),但Vue Router 4之后tag属性被移除了,现在更推荐用v-slot来自定义渲染结构(后面进阶部分会讲),不过新手阶段先掌握to属性的基本用法,就能完成大部分跳转需求~

和普通标签有啥区别?

很多同学会疑惑:既然都是“链接”,为啥不用标签?这得从单页应用(SPA)的原理说起——

普通标签跳转时,浏览器会重新请求服务器,刷新整个页面,但Vue做的是单页应用,所有页面切换都该在“前端内部”完成(只更新页面里的组件,不刷新整个页面),这时候就起到关键作用:

  1. 无刷新跳转基于Vue Router的路由模式(history或hash)实现“前端路由”,点击时只会更新页面里的组件,不会触发全页面刷新,体验更流畅。
  2. 自动管理激活状态:当当前路由和to路径匹配时,它会自动添加激活类(比如默认的router-link-active),方便做导航高亮,而标签得自己写JS判断路径来加类,麻烦多了。
  3. 传参更灵活to属性支持对象形式,能轻松传params(动态路由参数)、query(查询参数);标签只能手动拼接URL(比如<a href="/user?id=123">),不仅麻烦,还容易出错。

简单说:是“传统多页应用”的跳转方式,是“单页应用”的专属跳转组件,适配SPA的工作逻辑~

传参有哪些方式?

页面跳转时经常需要传数据(比如用户ID、筛选条件),主要靠paramsquery两种方式传参,用法和场景大不同:

params传参(动态路由参数)

适合路径中需要包含参数的场景(比如用户详情页/user/123,123是用户ID),步骤分两步:

  • 配置动态路由:在路由规则里用“:参数名”定义,
    const routes = [ 
      { path: '/user/:id', name: 'User', component: User } 
    ]
  • 里传参:用对象形式的to,通过params传值:
    <router-link :to="{ name: 'User', params: { id: 123 } }">用户123</router-link>

    这里必须用name匹配路由(用path的话params会被忽略,这点要注意!)。

特点:参数会嵌入URL路径(比如/user/123),刷新页面时参数不会丢失(因为路由配置里有/:id,属于路由的一部分),但如果路由没配置动态参数,直接用params传参,刷新后参数会消失哦~

query传参(查询参数)

适合可选参数、筛选条件这类场景(比如列表页的搜索关键词、分页页码),用法更简单:

直接在to的对象里加query属性,

<router-link :to="{ path: '/about', query: { msg: 'hello', page: 2 } }">关于页</router-link>

跳转后URL会变成/about?msg=hello&page=2

特点:参数在URL的后面,刷新页面时参数会保留(因为属于URL的一部分),但如果是敏感数据不适合用query(会暴露在URL里),用query传参时,to里用pathname都可以~

接收参数也很简单:在目标组件里通过this.$route.params.id(取params参数)或this.$route.query.msg(取query参数)就能拿到值~

如何给设置激活样式?

导航栏需要“当前页面高亮”是常见需求,内置了激活状态的自动管理,不用自己写JS判断,主要靠两个属性:

active-class:匹配时的激活类

to路径和当前路由“部分匹配”时,会自动添加active-class指定的类,默认类名是router-link-active,也可以自己定义:

比如想把激活类改成my-active

<router-link to="/home" active-class="my-active">首页</router-link>

然后在CSS里写.my-active的样式(比如改变文字颜色、加下划线)。

还能全局配置激活类:在创建路由实例时(createRouter),通过linkActiveClass选项统一设置,

const router = createRouter({ 
  history: createWebHistory(), 
  routes, 
  linkActiveClass: 'global-active-class' 
})

这样所有active-class都会变成global-active-class,不用每个组件重复写。

exact-active-class:精确匹配的激活类

有时候会遇到“路由嵌套”导致的激活问题,比如根路由是,子路由是/about,当跳转到/about时,的也会被激活(因为/about包含),这时候就需要精确匹配

exact属性,同时用exact-active-class指定精确匹配时的类:

<router-link to="/" exact exact-active-class="exact-active">首页</router-link>

这样只有当路径完全等于时,才会添加exact-active类,子路由跳转时就不会误激活啦~

嵌套路由里咋用?

很多项目有“父页面包含子页面”的结构(比如后台管理系统,左侧导航是父路由,右侧内容是子路由),这时候要配合嵌套路由配置来用。

先看路由配置的结构:

const routes = [ 
  { 
    path: '/dashboard', 
    component: Dashboard, 
    children: [ 
      { path: 'analysis', component: Analysis }, // 子路由,路径是/dashboard/analysis 
      { path: 'statistics', component: Statistics } 
    ] 
  } 
]

在父组件Dashboard的模板里,要跳转到子路由,可以用相对路径

<template> 
  <div class="dashboard"> 
    <router-link to="analysis">分析页</router-link> 
    <router-link to="statistics">统计页</router-link> 
    <router-view></router-view> <!-- 子路由组件渲染的地方 --> 
  </div> 
</template>

这里的to="analysis"相对路径,会自动拼接父路由的path/dashboard),变成/dashboard/analysis,如果用绝对路径,得写to="/dashboard/analysis",但相对路径更灵活,父路由path变化时不用改子路由的link~

如果子路由的path是空字符串(比如children{ path: '', component: Overview }),那跳转到父路由时会默认显示Overview组件,这时候<router-link to="" />就能跳转过去~

动态路由场景下怎么处理?

比如做“用户列表→用户详情”的功能,每个用户对应/user/:id,这时候需要循环渲染,并给每个用户传不同的id

假设用户数据是users数组,每个用户有idname,写法可以是:

<template> 
  <div class="user-list"> 
    <router-link 
      v-for="user in users" 
      :key="user.id" 
      :to="{ name: 'User', params: { id: user.id } }" 
    >{{ user.name }}</router-link> 
  </div> 
</template>

这里要注意路由组件复用的问题:当从/user/1跳转到/user/2时,User组件的实例会被复用(因为路由路径变化但组件相同),这时候组件的created钩子不会重新执行,导致数据没更新,解决办法有两种:

  1. 监听$route变化:在User组件里用watch监听$route
    watch: { 
      '$route' (to, from) { 
        // 这里获取to.params.id,重新请求数据 
      } 
    }
  2. 使用beforeRouteUpdate钩子:组件内定义
    beforeRouteUpdate(to, from, next) { 
      // 处理参数变化,更新数据 
      next() 
    }

所以动态路由场景下,负责跳转传参,而组件里要处理“参数变化但组件没销毁”的情况,确保数据能及时更新~

和编程式导航怎么配合?

Vue Router里除了这种“声明式导航”,还有编程式导航(比如this.$router.push()),两者各有适用场景,也能配合使用:

声明式 vs 编程式

是“声明式”,适合**模板里直接写跳转**(比如导航栏的链接),简单直观;编程式导航是“命令式”,适合**逻辑里判断后跳转**(比如登录成功后跳转到首页,需要先调接口验证)。

配合使用的场景

比如有个“提交表单”按钮,点击后要先验证表单,再跳转,这时候可以用<button>,点击事件里写逻辑,再调用编程式导航:

<template> 
  <button @click="handleSubmit">提交</button> 
</template> 
<script> 
export default { 
  methods: { 
    handleSubmit() { 
      if (this.formValid()) { // 验证表单 
        this.$router.push('/success') // 编程式导航跳转 
      } 
    } 
  } 
} 
</script>

但如果想保留的“激活状态管理”,又需要加点击逻辑,也可以给@click.native.prevent,在事件里处理逻辑后再跳转:

<router-link to="/success" @click.native.prevent="handleSubmit">提交</router-link>

这里.native是监听原生点击事件,.prevent是阻止默认跳转(因为要自己控制什么时候跳),在handleSubmit里处理完逻辑后,再调用this.$router.push('/success')

性能优化要注意啥?

如果项目里有大量(比如侧边栏有几十上百个导航项),或者路由配置很复杂,得注意这些优化点:

避免不必要的重渲染

本质是组件,大量重复渲染时可能影响性能,可以用**v-slot自定义渲染**,减少组件嵌套层级。 ```html ``` 这样不再渲染成`a`标签,而是自定义成`button`,还能通过`v-slot`拿到`navigate`(跳转方法)和`isActive`(是否激活),灵活控制渲染结构,减少默认组件的开销。

结合路由懒加载

路由懒加载是指“访问该路由时才加载对应的组件代码”,配置方式是在路由规则里用() => import('./views/Home.vue')的跳转不会影响懒加载的逻辑——点击时,才会触发对应组件的加载,所以合理用懒加载+能大幅降低首屏加载时间。

减少复杂计算在

如果to属性绑定的是一个复杂的计算属性或方法,每次组件渲染都会重新计算,拖慢速度,可以把计算逻辑提前到datacomputed里,再绑定给to

<script> 
export default { 
  computed: { 
    userPath() { 
      return { name: 'User', params: { id: this.userId } } 
    } 
  } 
} 
</script> 
<template> 
  <router-link :to="userPath">用户页</router-link> 
</template>

这样计算属性只会在依赖变化时重新计算,避免不必要的性能消耗~

到这里,从基础用法到传参、激活样式、嵌套路由、性能优化的常见问题就讲得差不多啦~其实核心就是理解它是Vue Router为SPA量身定制的“智能链接”,既解决了单页应用跳转不刷新的问题,又内置了激活状态、传参等实用功能,多结合项目场景练手,比如做个带导航栏、嵌套路由、动态传参的小Demo,就能彻底吃透它~

版权声明

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

发表评论:

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

热门