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

1.怎么快速搭建Vue Router 3.x的基础路由?

terry 7小时前 阅读数 9 #Vue
文章标签 x;基础路由

在Vue 2项目开发里,Vue Router 3.x是实现单页面应用路由管理的核心工具,不管是做后台管理系统的页面跳转,还是移动端App的多页面切换,它都能帮我们把页面逻辑梳理得明明白白,但实际开发时,不少同学会卡在路由配置、传参、模式选择这些环节,今天就用问答形式,把Vue Router 3.x开发中常见的问题和解决思路聊透,帮你少踩坑~

要在Vue 2项目里用Vue Router 3.x,步骤其实很清晰:

首先得安装依赖,打开终端执行 npm install vue-router@3(指定3.x版本,避免装到适配Vue 3的4.x版本)。

然后创建路由配置文件,比如在src下新建router/index.js,基本结构长这样:

import Vue from 'vue'
import VueRouter from 'vue-router'
// 导入页面组件,这里用常规导入,后面讲懒加载时再换写法
import Home from '@/views/Home.vue'
import About from '@/views/About.vue'
Vue.use(VueRouter) // 全局注册VueRouter插件
const routes = [
  {
    path: '/', // 访问根路径时
    name: 'Home',
    component: Home // 渲染Home组件
  },
  {
    path: '/about',
    name: 'About',
    component: About
  }
]
const router = new VueRouter({
  routes // 把定义好的路由规则传进去
})
export default router

接着要把路由实例挂载到Vue根实例上,打开src/main.js

import Vue from 'vue'
import App from './App.vue'
import router from './router' // 导入上面写的路由配置
new Vue({
  router, // 注入路由,让所有组件能通过this.$router/$route访问
  render: h => h(App)
}).$mount('#app')

最后在App.vue里加入路由出口(<router-view></router-view>)和导航(<router-link>):

<template>
  <div id="app">
    <!-- 导航链接,to属性对应路由path -->
    <router-link to="/">首页</router-link>
    <router-link to="/about">lt;/router-link>
    <!-- 路由匹配到的组件会渲染到这里 -->
    <router-view></router-view>
  </div>
</template>

这样一套操作下来,就能实现基础的页面跳转了,重点是记住“安装插件→定义路由规则→挂载路由→用router-view和router-link渲染”这几个步骤~

hash模式和history模式有啥区别?该怎么选?

Vue Router 3.x支持两种路由模式,配置是通过new VueRouter时的mode选项:

  • hash模式(默认):URL里会带个,比如http://xxx.com/#/home,它的原理是利用URL的hash(锚点)变化不会触发页面刷新,浏览器会监听hashchange事件,进而更新路由,这种模式对老浏览器(比如IE9)兼容性更好,而且部署时不需要后端额外配置,因为服务器只需要返回首页HTML,路由由前端自己处理。

  • history模式:URL更“干净”,像http://xxx.com/home这样,它依赖HTML5的history.pushState API来实现URL变化但不刷新页面,优点是URL美观,和普通网站的URL结构一致;但缺点是部署时需要后端配合——如果用户直接访问某个子路由(比如http://xxx.com/about),服务器没有对应的资源,就会返回404,这时候需要后端配置“所有请求都重定向到index.html”,让前端路由接管。

选的时候看项目需求:如果是对内系统、对兼容性要求高(比如要兼容IE),用hash模式省心;如果是对外的官网、需要URL更友好,且能配合后端做路由重定向,就用history模式,切换模式也很简单,改一下路由配置:

const router = new VueRouter({
  mode: 'history', // 换成history,默认是hash
  routes
})

路由传参有哪些方式?各自适合啥场景?

Vue Router 3.x里传参主要有动态路由(params)查询参数(query)props传参这三种方式,用法和场景各有不同:

① 动态路由(params)

适合需要把参数“嵌入”URL的场景,比如用户详情页/user/1,其中1是用户ID,配置时要在路由规则里定义动态段:

{
  path: '/user/:id', // :id是动态参数
  name: 'User',
  component: User
}

跳转时可以用router-link

<router-link :to="{ name: 'User', params: { id: 1 }}">用户1</router-link>

或者编程式导航:

this.$router.push({ name: 'User', params: { id: 1 }})

组件内获取参数用this.$route.params.id,这种方式的好处是参数在URL里可见,刷新页面参数也不会丢;但如果参数多了,URL会很长,而且参数是必填的(比如访问/user会匹配不到路由,除非配置了默认值)。

② 查询参数(query)

类似URL里的查询字符串,比如/user?name=张三&age=18,参数跟在后面,配置路由时不需要改path,直接在跳转时传query对象:

<router-link :to="{ path: '/user', query: { name: '张三', age: 18 }}">用户页</router-link>

编程式导航:

this.$router.push({ path: '/user', query: { name: '张三', age: 18 }})

组件内用this.$route.query.name获取,这种方式适合可选参数,比如搜索页的筛选条件,不传参数也能正常访问页面,而且参数可以多个,灵活性高;但缺点是参数暴露在URL里,不太适合敏感信息。

③ props传参

能让路由组件和参数“解耦”,更符合组件化思想,开启props有三种方式:

  • 布尔模式:路由配置里设props: true,此时组件可以通过props接收$route.params的参数:

    {
      path: '/user/:id',
      component: User,
      props: true // 开启后,User组件可以用props: ['id']接收
    }
  • 对象模式:适合传固定值,不管URL怎么变,props值不变:

    {
      path: '/page',
      component: Page,
      props: { title: '固定标题' } // Page组件用props: ['title']接收
    }
  • 函数模式:最灵活,可以对参数做处理,比如结合query和params:

    {
      path: '/article',
      component: Article,
      props: route => ({ 
        id: route.query.id, 
        type: route.params.type 
      })
    }

用props的好处是组件不需要依赖$route,更易测试和复用;缺点是如果参数多,配置起来稍麻烦。

总结下来:需要URL体现参数、参数必填→用动态路由;可选参数、多参数→用query;想让组件更纯净→用props~

导航守卫怎么用?能解决哪些实际问题?

导航守卫就是路由切换过程中的“钩子函数”,能在路由跳转前、后做拦截或处理,常见的有全局守卫路由独享守卫组件内守卫三类,每个场景都有对应的用法:

① 全局守卫(控制全局权限)

比如全局判断用户是否登录,没登录就跳登录页,用router.beforeEach,在路由配置文件里写:

router.beforeEach((to, from, next) => {
  // to: 要跳转到的目标路由;from: 从哪个路由来;next: 必须调用的函数,决定是否跳转
  const isLogin = localStorage.getItem('token') // 假设用localStorage存登录态
  if (to.name !== 'Login' && !isLogin) { 
    next({ name: 'Login' }) // 没登录且不是登录页,跳登录
  } else {
    next() // 放行
  }
})

除了权限,还能做全局loading:跳转时显示loading,成功后隐藏,结合router.beforeEachrouter.afterEach(afterEach没有next,只做回调)。

② 路由独享守卫(单个路由的拦截)

比如某个页面需要特殊权限,在路由规则里加beforeEnter

{
  path: '/admin',
  name: 'Admin',
  component: Admin,
  beforeEnter: (to, from, next) => {
    const isAdmin = localStorage.getItem('isAdmin')
    if (isAdmin) {
      next()
    } else {
      next({ name: 'Home' }) // 不是管理员跳首页
    }
  }
}

③ 组件内守卫(组件生命周期内的路由处理)

常用的有beforeRouteEnter(进入组件前,此时组件实例还没创建,不能用this)、beforeRouteUpdate(路由复用组件时触发,比如从/user/1/user/2,组件复用,需要更新数据)、beforeRouteLeave(离开组件前,比如判断表单是否修改,提示用户)。

举个beforeRouteUpdate的例子,用户页复用组件时更新数据:

export default {
  name: 'User',
  data() { return { userInfo: {} } },
  beforeRouteUpdate(to, from, next) {
    // to.params.id是新的用户ID
    this.fetchUser(to.params.id) // 调用接口重新获取数据
    next()
  },
  methods: {
    fetchUser(id) {
      // 发请求获取用户信息
    }
  }
}

导航守卫的核心是控制路由流向处理页面切换时的逻辑,比如权限、数据预加载、页面离开提示这些场景,都能靠它解决~

路由懒加载怎么配置?对性能有啥帮助?

路由懒加载本质是按需加载组件,让首屏不需要加载所有页面的代码,等用户访问对应路由时再加载,从而减小首屏体积、加快加载速度。

Vue Router 3.x里配置懒加载很简单,把原来的静态导入(import Home from '@/views/Home.vue')换成动态导入

const Home = () => import('@/views/Home.vue')
const About = () => import('@/views/About.vue')
const routes = [
  { path: '/', component: Home },
  { path: '/about', component: About }
]

这里的import()是ES6的动态导入语法,Webpack会自动把每个组件打包成单独的chunk(代码块),访问对应路由时才会加载这个chunk。

对性能的帮助很直观:假设项目有10个页面,首屏只加载首页和必要组件,其他9个页面的代码等到用户点击时再加载,首屏JS体积能减少一大半,加载速度自然更快,尤其是页面多、组件大的项目,懒加载能明显提升用户体验。

如果想给 chunk 命名(方便调试),可以用Webpack的魔法注释:

const Home = () => import(/* webpackChunkName: "home" */ '@/views/Home.vue')

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

嵌套路由就是“父路由里包含子路由”,典型场景是后台管理系统:比如有个Layout组件(包含侧边栏、顶栏),里面嵌套DashboardSettings等子页面。

配置时用children数组,父路由的组件里必须有<router-view></router-view>来显示子路由:

第一步,定义路由规则(router/index.js):

const Layout = () => import('@/views/Layout.vue')
const Dashboard = () => import('@/views/Dashboard.vue')
const Settings = () => import('@/views/Settings.vue')
const routes = [
  {
    path: '/admin',
    component: Layout, // 父组件,包含侧边栏等公共布局
    children: [
      {
        path: 'dashboard', // 注意!这里path不加/,会自动拼接成/admin/dashboard
        name: 'Dashboard',
        component: Dashboard
      },
      {
        path: 'settings',
        name: 'Settings',
        component: Settings
      }
    ]
  }
]

第二步,在父组件Layout.vue里加入子路由出口:

<template>
  <div class="layout">
    <!-- 侧边栏、顶栏等公共部分 -->
    <aside>侧边栏</aside>
    <header>顶栏</header>
    <!-- 子路由组件渲染到这里 -->
    <router-view></router-view>
  </div>
</template>

设计嵌套路由的关键是明确页面层级:父路由负责公共布局,子路由负责具体页面内容,这样做能让代码结构更清晰,避免重复写布局组件~

动态路由匹配和路由参数怎么处理?

动态路由匹配指的是路由规则里有动态段(比如/user/:id),当从/user/1跳转到/user/2时,Vue Router会复用组件实例(因为组件一样),这时候组件的created钩子不会重新执行,导致数据没更新。

这时候有两种解决办法:

① 监听$route变化

在组件里用watch监听$route,路由变化时更新数据:

export default {
  name: 'User',
  data() { return { userInfo: {} } },
  watch: {
    '$route'(to) {
      this.fetchUser(to.params.id) // 路由变化时重新请求数据
    }
  },
  methods: {
    fetchUser(id) { /* 发请求 */ }
  }
}

② 使用组件内守卫beforeRouteUpdate

这种方式更“针对性”,只处理路由更新的情况:

export default {
  name: 'User',
  data() { return { userInfo: {} } },
  beforeRouteUpdate(to, from, next) {
    this.fetchUser(to.params.id)
    next() // 必须调用next放行
  },
  methods: {
    fetchUser(id) { /* 发请求 */ }
  }
}

如果需要在路由跳转前就获取数据(比如进入页面时数据已经准备好),可以用导航守卫配合异步请求,比如在beforeRouteEnter里发请求,数据回来后再进入页面~

路由出错(比如404页面)怎么处理?

项目里难免遇到用户输错地址、访问不存在的路由的情况,这时候要跳转到404页面,配置思路是*用通配符路由()匹配所有未定义的路径,但要注意路由的匹配顺序——通配符路由必须放在routes数组的最后面**,因为Vue Router是从上到下匹配路由的。

步骤如下:

第一步,创建NotFound.vue组件,显示“页面不存在”之类的提示。

第二步,在路由规则里添加通配符路由:

const NotFound = () => import('@/views/NotFound.vue')
const routes = [
  // 其他路由规则...
  {
    path: '*', // 匹配所有未定义的路径
    name: 'NotFound',
    component: NotFound
  }
]

这样,当用户访问不存在的路径时,就会渲染NotFound组件,如果项目用了history模式,还要确保后端配置了“所有未知请求都返回index.html”,否则直接访问/abc这种路径,服务器会返回404,而不是前端的404页面~

Vue Router 3.x和Vue 2.x版本适配要注意啥?

Vue Router的版本和Vue版本是强绑定的:Vue 2对应Vue Router 3.x,Vue 3对应Vue Router 4.x,如果搞错版本,会出现各种兼容问题,

  • 安装时如果直接执行npm install vue-router,默认会装最新的4.x版本,而Vue 2项目用不了,会报类似“export 'createRouter' was not found in 'vue-router'”的错误(因为Vue Router 4用createRouter创建实例,而3.x是new Router)。

所以正确的做法是指定版本安装

npm install vue-router@3

Vue Router 3.x的API和4.x有很大区别,

  • x用new VueRouter({ routes })创建实例,4.x用createRouter
  • x的模式是mode: 'history',4.x是history: createWebHistory()
  • 导航守卫的语法也有变化(比如3.x的beforeRouteEnter在4.x里写法不同)。

如果项目是Vue 2,一定要用Vue Router 3.x;如果

版权声明

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

发表评论:

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

热门