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

vue-router npm 是什么?怎么在项目里用?常见问题咋解决?

terry 4小时前 阅读数 9 #Vue
文章标签 router npm

想搞懂vue-router npm 咋回事、咋在项目里用,还有碰到问题咋解决?这篇从基础到实操,把常见疑问拆明白,不管是刚学Vue的新手,还是想优化路由配置的老手,都能找到有用的点~

vue-router npm 是干啥的?

首先得拆成两部分理解:vue-router 是Vue.js官方的路由管理工具,专门解决单页应用(SPA)里“页面”切换、URL管理这些事儿;npm 是Node.js的包管理工具,我们通过npm把vue-router装到项目里,就像在手机应用商店下App一样。

单页应用最大特点是整站只有一个HTML文件,用户切换“页面”时不刷新浏览器,靠JS动态渲染组件,vue-router就是干这个的:它能让不同路径(/home/about)对应不同组件,还支持嵌套路由(像后台管理系统的侧边栏+内容区结构)、动态路由(/user/123 里的用户ID)、路由守卫(控制页面权限、跳转逻辑)这些核心功能,要是没有它,你得自己写一堆逻辑判断URL变化、渲染不同组件,麻烦到哭~

怎么用npm装vue-router到项目里?

步骤不难,但得注意Vue版本!Vue2和Vue3对应的vue-router版本不一样,装错了容易报错:

  • Vue2项目:装 vue-router@3,命令是 npm install vue-router@3
  • Vue3项目:装 vue-router@4,命令是 npm install vue-router(因为@4是默认最新版)。

装好后得配置路由,以Vue3 + Vite项目为例,流程大概这样:

新建路由配置文件

src 文件夹下建 router 文件夹,里面写 index.js

引入并创建路由实例

// src/router/index.js
import { createRouter, createWebHistory } from 'vue-router'
// 引入你写的页面组件,比如Home和About
import Home from '../views/Home.vue'
import About from '../views/About.vue'
const routes = [
  {
    path: '/', // 根路径
    name: 'Home',
    component: Home
  },
  {
    path: '/about',
    name: 'About',
    component: About
  }
]
const router = createRouter({
  history: createWebHistory(), // 路由模式用history(URL里没#),想兼容旧浏览器用createWebHashHistory()
  routes // 上面定义的路由规则数组
})
export default router

把路由挂载到Vue实例

打开 src/main.js,引入路由并use:

// src/main.js
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> 显示匹配的组件,用 <router-link to="/about">关于页</router-link> 做跳转链接,路由就跑起来啦~

vue-router配置路由有哪些关键步骤?

核心就四点:路由映射、模式选择、特殊路由(嵌套/动态)、导航方式,一个个说:

路由映射:path和component绑定

每个路由规则是个对象,path 是URL路径,component 是对应要渲染的Vue组件,比如用户访问 /product,就显示 Product.vue 组件,还能给路由加 name(命名路由),跳转时用name更稳,不怕path改了要全局替换。

路由模式:history vs hash

两种模式决定URL长啥样:

  • history模式:URL像 https://xxx.com/about,好看但需要后端配置(否则刷新404);
  • hash模式:URL带 ,像 https://xxx.com/#/about,兼容性好(老浏览器也支持),不用后端配。

Vue3里用 createWebHistory()createWebHashHistory() 选模式,Vue2里是 new VueRouter({ mode: 'history' })

特殊路由:嵌套和动态

嵌套路由

适合有公共布局的场景(比如后台管理系统,侧边栏是固定的,内容区换组件),配置时用 children 数组,父路由组件里得有 <router-view> 渲染子路由:

const routes = [
  {
    path: '/admin',
    component: AdminLayout, // 父组件,里面有侧边栏+<router-view>
    children: [
      { path: 'dashboard', component: Dashboard }, // 子路由,访问/admin/dashboard
      { path: 'settings', component: Settings }
    ]
  }
]

动态路由

处理带参数的路径,/user/123 里的用户ID,配置时用 /user/:id,组件里通过 $route.params.id(Vue2)或 useRoute().params.id(Vue3)拿参数。

导航方式:声明式和编程式

  • 声明式:用 <router-link to="/path"> 写在模板里,自动生成a标签,还能控制激活样式;
  • 编程式:用 router.push('/path') 写在JS里(比如点击按钮后跳转),灵活度高,还能传参(后面讲传参时细说)。

单页应用里,vue-router咋处理页面跳转和传参?

跳转分声明式编程式,传参分queryparams,组合起来有四种玩法,先看跳转:

声明式跳转(<router-link>

基础用法:<router-link to="/about">去关于页</router-link>,点击就跳。
传参的话,分query和params:

  • query传参:URL带参数,像 /about?name=张三,配置:<router-link :to="{ path: '/about', query: { name: '张三' }}"></router-link>
  • params传参:参数藏在路由path里(需要路由配置时写 /user/:id),配置:<router-link :to="{ name: 'User', params: { id: 123 }}"></router-link>(注意要用name,不能用path,否则params传不过去)。

编程式跳转(router.push

在JS里写,比如按钮点击事件:

// Vue2:this.$router.push
methods: {
  goAbout() {
    this.$router.push('/about')
    // 传query:
    this.$router.push({ path: '/about', query: { name: '张三' } })
    // 传params(要配合命名路由):
    this.$router.push({ name: 'User', params: { id: 123 } })
  }
}
// Vue3:用useRouter
import { useRouter } from 'vue-router'
const router = useRouter()
const goAbout = () => {
  router.push('/about')
  // 传参和Vue2逻辑一样
}

传参后咋接收?

目标组件里,用 $route.query$route.params 拿参数(Vue3用 useRoute().query / useRoute().params):

// Vue2组件里
export default {
  mounted() {
    console.log(this.$route.query.name) // 拿query参数
    console.log(this.$route.params.id) // 拿params参数(路由得配了/:id)
  }
}
// Vue3组件(组合式API)
import { useRoute } from 'vue-router'
const route = useRoute()
console.log(route.query.name)
console.log(route.params.id)

注意:params传参如果没在路由path里定义(比如路由path是/user,没写/user/:id),刷新页面参数会丢!因为params不显示在URL里;而query参数在URL里,刷新也能保留,所以如果需要刷新不丢参,优先用query,或者把params对应的参数写到路由path里。

vue-router碰到404页面咋配置?

核心思路是“通配符路由”,让所有没匹配到的路径都跳404组件,但得注意Vue2和Vue3的写法区别:

Vue3里的404配置

路由规则最后加个通配符路由:

const routes = [
  // 其他路由...
  {
    path: '/:pathMatch(.*)*', // 匹配所有没定义的路径,括号里的(.*)是正则,*表示可选
    name: 'NotFound',
    component: () => import('../views/NotFound.vue') // 也可以用懒加载
  }
]

NotFound.vue 里就写“页面走丢啦~返回首页?”之类的提示,再加个返回按钮用 router.push('/') 跳回去。

Vue2里的404配置

写法更简单,用 path: '*'

const routes = [
  // 其他路由...
  {
    path: '*',
    component: NotFound
  }
]

不管Vue2还是Vue3,404路由必须放最后!因为路由是“从上到下”匹配的,前面的精确路由要优先匹配,最后再匹配通配符,不然把正常路由也截胡成404了。

vue-router嵌套路由咋玩?实际项目里常用吗?

嵌套路由在中大型项目里超级常用!比如电商网站的商品列表页点进商品详情,或者后台管理系统的布局(顶部导航+侧边栏+内容区),它的核心是“路由里套路由”,父路由组件里有 <router-view> 来渲染子路由组件。

举个后台管理系统的例子:

// 路由配置
const routes = [
  {
    path: '/admin',
    component: AdminLayout, // 父组件,包含侧边栏和<router-view>
    children: [
      { path: 'dashboard', component: Dashboard }, // 子路由1:仪表盘
      { path: 'orders', component: OrderList }, // 子路由2:订单列表
      { path: 'products', component: ProductManage } // 子路由3:商品管理
    ]
  }
]
// AdminLayout.vue(父组件)
<template>
  <div class="admin-layout">
    <aside>侧边栏:<router-link to="dashboard">仪表盘</router-link> | <router-link to="orders">订单</router-link></aside>
    <main><router-view></router-view></main> <!-- 子路由组件渲染在这 -->
  </div>
</template>

用户访问 /admin/dashboard 时,AdminLayout 会渲染,Dashboard 组件渲染在 <router-view> 里,这样做的好处是布局复用(侧边栏不用每个页面都写一遍)、代码拆分清晰(不同功能模块的路由集中管理)。

vue-router动态路由和路由传参有啥坑?咋避?

踩过这些坑的人不少,总结三个高频坑和解决方法:

坑1:params传参刷新后丢失

场景:用 router.push({ name: 'User', params: { id: 123 } }) 跳转,URL是 /user(没把id写进path),刷新页面后 $route.params.id 没了。
原因:params参数没出现在URL里,属于“内存式”传参,刷新就没了。
解决:要么把参数放到query里(query: { id: 123 }),要么在路由path里定义 /user/:id,让参数显示在URL中(如 /user/123),这样刷新也能保留。

坑2:动态路由组件复用,生命周期不触发

场景:从 /user/1 跳到 /user/2,两个页面用同一个组件(UserDetail.vue),这时候组件实例会复用,mounted 钩子不会重新执行,导致数据没更新。
解决

  • watch 监听路由变化:

    // Vue2
    export default {
      watch: {
        '$route' (to, from) {
          // to是目标路由,from是来源路由
          this.fetchData(to.params.id) // 重新拉取数据
        }
      }
    }
    // Vue3(组合式API)
    import { watch } from 'vue'
    import { useRoute } from 'vue-router'
    const route = useRoute()
    watch(route, (to) => {
      fetchData(to.params.id)
    }, { immediate: true })
  • <router-view> 加key,强制组件重新渲染:<router-view :key="$route.fullPath" />(fullPath包含路径和参数,参数变了key就变,组件重新加载)。

坑3:query传参是对象/数组,URL解析异常

场景:想传个对象 { name: '张三', age: 18 } 到query里,结果URL变成 /path?query=%5Bobject%20Object%5D,取的时候解析出错。
原因:query参数会被转成字符串,对象/数组直接转会乱码。
解决:用 JSON.stringify 转成字符串传,取的时候 JSON.parse 解析:

// 传参时
router.push({
  path: '/path',
  query: {
    info: JSON.stringify({ name: '张三', age: 18 })
  }
})
// 取参时
const info = JSON.parse(route.query.info)

vue-router路由守卫咋用?能解决啥问题?

路由守卫就是“在路由跳转的各个阶段插一脚”,控制权限、处理逻辑,分三类:全局守卫、路由独享守卫、组件内守卫

全局守卫:控制所有路由

最常用的是 router.beforeEach(跳转前拦截)和 router.afterEach(跳转后执行),比如做权限控制:用户没登录,就跳转到登录页。

// src/router/index.js
router.beforeEach((to, from, next) => {
  // to:要去的路由;from:从哪来的路由;next:放行/跳转的函数
  const isLogin = localStorage.getItem('token') // 假设用localStorage存登录状态
  if (to.meta.requiresAuth && !isLogin) { // 路由元信息requiresAuth为true时需要登录
    next('/login') // 没登录,跳登录页
  } else {
    next() // 放行
  }
})
// 路由规则里加meta
{
  path: '/order',
  component: Order,
  meta: { requiresAuth: true } // 需要登录才能访问
}

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

在路由规则里写 beforeEnter,比如某个路由需要检查参数是否合法:

{
  path: '/user/:id',
  component: UserDetail,
  beforeEnter: (to, from, next) => {
    const id = to.params.id
    if (/^\d+$/.test(id)) { // 检查id是否是数字
      next()
    } else {
      next('/404') // 不是数字,跳404
    }
  }
}

组件内守卫:组件里的生命周期

常用 beforeRouteLeave(离开组件前拦截),比如用户填了表单没保存,离开时提示:

// Vue2组件
export default {
  data() { return { formDirty: false } },
  beforeRouteLeave(to, from, next) {
    if (this.formDirty) {
      if (window.confirm('表单没保存,确定离开?')) {
        next() // 确定就放行
      } else {
        next(false) // 取消就留在当前页
      }
    } else {
      next()
    }
  }
}
// Vue3组件(选项式API里写,组合式API用onBeforeRouteLeave)
import { onBeforeRouteLeave } from 'vue-router'
export default {
  setup() {
    const formDirty = ref(false)
    onBeforeRouteLeave((to, from, next) => {
      if (formDirty.value) {
        // 同上逻辑
      }
    })
    return { formDirty }
  }
}

这些守卫能解决的问题太多了:权限控制、数据预加载(进入路由前先拉数据)、离开页面确认、埋点统计(afterEach里记跳转次数)……

vue2和vue3里的vue-router用法有啥不一样?

Vue2用 vue-router@3,Vue3用 vue-router@4,核心区别在创建路由的方式、API风格、路由模式写法、组件内使用方式这些地方:

创建路由实例

Vue2:new VueRouter({ routes, mode })
Vue3

版权声明

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

发表评论:

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

热门