Vue.js【路由】

初识路由

提到路由Route),一般我们会联想到网络中常见的路由器Router),那么路由和路由器之间有什么关联呢?路由是指路由器从一个接口接收到数据根据数据的目的地址将数据定向传送到另一个接口的行为和动作;而路由器是执行行为和动作的硬件设备,主要用于连接网络,实现不同网络之间的通信和数据传递。

根据技术的不同,Web开发中的路由分为后端路由前端路由 

后端路由的整个过程发生在服务器端,开发者需要在服务器端程序中建立一套后端路由规则。当服务器接收到请求后,会通过路由寻找当前请求的URL地址对应的处理程序。

前端路由的整个过程发生在浏览器端,其特点是当URL地址改变时不需要向服务器发起一个加载新页面的请求,而是在维持当前页面的情况下切换页面中显示的内容。

1.后端路由

后端路由规则和处理程序都是开发人员事先编写的代码。当服务器接收到浏览器的请求后,会通过app.get()方法根据URL地址中的路径寻找对应的处理程序。

下面以Node.js环境中的Express框架中的路由为例,演示后端路由的工作原理如下图所示。

2.前端路由

下面以Vue中的路由为例,演示前端路由的工作原理。

Vue中的路由有Hash模式和HTML5模式,具体介绍如下。

Hash模式

Hash模式的前端路由通过URL中从#”开始的部分实现不同组件之间的切换,#”表示Hash,“#”后面的值称为Hash,该值将用于进行路由匹配。Hash模式前端路由的工作原理如下图所示。

HTML5模式

HTML5模式的URL地址与后端路由的URL地址的风格一致,可以通过URL地址中的路径进行路由匹配。HTML5模式前端路由的工作原理如下图所示。

初识Vue Router

Vue Router有多个版本,其中,Vue Router 4适用于Vue 3,而Vue Router 3适用于Vue 2。由于本书重点讲解Vue 3,所以接下来将基于Vue Router4进行讲解。

Vue Router的基本使用

路由的基本使用步骤分为以下4步。

1.定义路由组件

src\components目录下创建Home.vue文件和About.vue文件。

<!-- Home.vue文件 -->
<template>
  <div class="home-container">
    <h3>Home组件</h3>
  </div>
</template>
<style scoped>
.home-container {
  min-height: 150px;
  background-color: #f2f2f2;
  padding: 15px;
}
</style>
<!-- About.vue文件 -->
<template>
  <div class="about-container">
    <h3>About组件</h3>
  </div>
</template>
<style scoped>
.about-container {
  min-height: 150px;
  background-color: #f2f2f2;
  padding: 15px;
}
</style>

2.定义路由链接和路由视图

使用<router-view>标签定义路由视图,该标签会被渲染成当前路由对应的组件。通过<router-link>标签定义路由链接方便在不同组件之间切换。

<template>
  <div class="app-container">
    <h1>App根组件</h1>
    <router-link to="/home">首页</router-link>
    <router-link to="/about">关于</router-link>
    <hr>
    <router-view></router-view>
  </div>
</template>
<style scoped>
.app-container {
  text-align: center;
  font-size: 16px;
}
.app-container a {
  padding: 10px;
  color: #000;
}
.app-container a.router-link-active {
  color: #fff;
  background-color: #000;
}
</style>

3.创建路由模块

① 在src目录下创建router.js文件作为路由模块,并在该文件中导入路由相关函数

import { createRouter, createWebHashHistory } from 'vue-router'

② 在router.js文件中导入需要被路由控制的Home组件和About组件。

import Home from './components/Home.vue'
import About from './components/About.vue'

③ 在router.js文件中创建路由实例对象

const router = createRouter({
  history: createWebHashHistory(),
  routes: [
    { path: '/home', component: Home },
    { path: '/about', component: About },
  ]
})

注意:

步骤②和③的组件加载方式是一次加载所有组件,除了这种方式外,还可以通过懒加载的方式动态加载组件。

④ 在router.js文件中导出路由实例对象

export default router

下面讲解如何通过懒加载的方式动态加载组件。

删除第②步的代码。将第③步的代码修改为如下代码。

const router = createRouter({
  history: createWebHashHistory(),
  routes: [
    { path: '/home', component: () => import('./components/Home.vue') },
    { path: '/about', component: () => import('./components/About.vue') },
  ]
})

4. 导入并挂载路由模块

src\main.js文件中导入并挂载路由模块。

import { createApp } from 'vue'
import './style.css'
import App from './App.vue'
import router from './router.js'	// 导入路由模块
const app = createApp(App)
app.use(router)		// 挂载路由模块
app.mount('#app')

执行yarn dev命令启动服务。服务启动成功后,在浏览器中访问http://127.0.0.1:5173/,使用路由后的初始页面效果、单击“首页”路由链接后的Home组件的效果、单击“关于”路由链接后的About组件的效果如下图所示。

多学一招:更改路由链接激活项的类名

在默认情况下,路由链接激活项的类名为router-link-active。如果需要更改类名,可以在创建路由实例对象时通过linkActiveClass属性设置一个类名。

const router = createRouter({
  linkActiveClass: 'router-active',
  ……
})

路由重定向

在开发过程中,可能希望当用户访问不同的路径时,页面中显示同一个组件,这时就需要用到路由重定向。路由重定向可以使用户在访问一个URL地址时,强制跳转到另一个URL地址,从而展示特定的组件。通过路由匹配规则中的redirect属性可以指定一个新的路由地址,从而实现路由重定向。

下面演示路由重定向的使用方法。

修改src\router.js文件,实现当用户访问“/路径时,将路由重定向到“/home路径。

const router = createRouter({
  history: createWebHashHistory(),
  routes: [
    { path: '/', redirect: '/home' },
    { path: '/home', component: import ('./components/Home.vue') },
    { path: '/about', component: import('./components/About.vue') }
  ]
})

嵌套路由

嵌套路由是指通过路由实现组件的嵌套展示,它主要由页面结构决定。实际项目中的应用界面通常由多层嵌套的组件组合而成,为了使多层嵌套的组件能够通过路由访问,路由也需要具有嵌套关系,也就是在路由里面嵌套它的子路由。

下面演示嵌套路由的简单配置。

src\router.js文件的路由匹配规则中通过children属性定义子路由匹配规则

routes: [
  {
    path: '父路由路径', 
    component: 父组件,
    children: [
      { path: '子路由路径1', component: 子组件1 },
      { path: '子路由路径2', component: 子组件2 }
    ]
  }
]

在组件中定义子路由链接的语法格式如下。

<router-link to="/父路由路径/子路由路径"></router-link>

注意:

当使用children属性定义子路由匹配规则时,子路由的path属性前不要带“/”,否则会永远以根路径开始请求。

步骤2

创建src\components\pages\Tab1.vue文件。

<template>
  <div>Tab1组件</div>
</template>
<style scoped>
div {
  text-align: left;
  background-color: #9dc4e5;
}
</style>

步骤3

创建src\components\pages\Tab2.vue文件。

<template>
  <div>Tab2组件</div>
</template>
<style scoped>
div {
  text-align: left;
  background-color: #ffba00;
}
</style>

步骤4

component\About.vue文件中添加子路由链接子路由视图

<template>
  <div class="about-container">
    <h3>About组件</h3>
    <router-link to="/about/tab1">tab1</router-link>
    <router-link to="/about/tab2">tab2</router-link>
    <hr>
    <router-view></router-view>
  </div>
</template>
<style scoped>
.about-container {
min-height: 150px;
  background-color: #f2f2f2;
  padding: 15px;
}
.about-container a {
  padding: 10px;
  border: 1px solid #ccc;
  border-radius: 5px;
  padding: 5px 10px;
  color: #000;
  margin: 0 5px;
}
.about-container a.router-link-active {
  color: #000;
  background-color: #deebf6;
}
</style>

步骤5

修改src\router.js文件,在routes导入Tab1组件和Tab2组件,并使用children属性定义子路由匹配规则

routes: [
  { path: '/', redirect: '/about' },
  { path: '/home', component: () => import ('./components/Home.vue') },
  {
    path: '/about', component: () => import('./components/About.vue'),
    children: [
      { path: 'tab1', component: () => import ('./components/pages/Tab1.vue') },
      { path: 'tab2', component: () => import ('./components/pages/Tab2.vue') }]
  }]

在浏览器中访问http://127.0.0.1:5173/。页面打开后,会自动重定向到About组件的路由,页面显示About组件;单击“tab1”链接,页面显示About组件中的Tab1组件;单击“tab2”链接,页面显示About组件中的Tab2组件,如下图所示。

动态路由

动态路由概述

动态路由是一种路径不固定的路由,路径中可变的部分被称为动态路径参数Dynamic Segment),使用动态路径参数可以提高路由规则的可复用性。在Vue Router的路由路径中,使用“:参数名”的方式可以在路径中定义动态路径参数。

下面通过代码演示如何定义一个动态路由。

注意

不同动态路径参数的动态路由在进行切换时,由于它们都是指向同一组件,所以Vue不会销毁再重新创建这个组件,而是复用这个组件。如果想要在切换时进行一些操作,就需要在组件内部利用watch来监听路由的变化。

下面演示如何在About组件中监听路由的变化。

About组件中利用watch监听路由的变化。

<script setup>
import { useRoute } from 'vue-router'
import { watch } from 'vue'
const route = useRoute()
watch(() => route.path, path => {
  console.log('路由路径', path)
})
</script>

在浏览器中访问http://127.0.0.1:5173/依次单击子路由链接“tab1”和“tab2”,监听路由变化的效果,如下图所示。

获取动态路径参数值

获取动态路径参数值的2种方式:使用$route.params获取参数值使用props获取参数值

使用$route.params获取参数值

新建src\components\Movie.vue文件,在该文件中定义3路由链接路由视图

<template>
  <div class="movie-container">
    <router-link to="/movie/1">电影1</router-link>
    <router-link to="/movie/2">电影2</router-link>
    <router-link to="/movie/3">电影3</router-link>
    <router-view></router-view>
  </div>
</template>
<style>
.movie-container {
min-height: 150px;
  background-color: #f2f2f2;
}
.movie-container a {
  padding: 0 5px;
  font-size: 18px;
  border: 1px solid #ccc;
  border-radius: 5px;
  color: #000;
  margin: 0 5px;
}
</style>

Movie组件初始页面效果、单击“电影1”链接,跳转到MovieDetails组件的效果,如下图所示。

使用props获取参数值Vue Router允许在路由匹配规则中开启props传参。

① 修改src\components\MovieDetails.vue文件,使用props接收路由规则中匹配到的参数

<template>
  <p>电影{{ id }}页面</p>
</template>
<script setup>
const props = defineProps({
  id: String
})
</script>

② 在src\router.js文件中,为:id”路径的路由开启props传参

{
  path: ':id', 
  component: () => import          ('./components/movieDetails.vue'), 
  props: true 
}

命名路由

使用路由时,一般会先在routes属性中配置路由匹配规则,然后在页面中使用<router-link>to属性跳转到指定目标地址。但这种方式存在一些弊端,例如,当目标地址比较复杂时,不便于记忆;当地址发生变化时,需要同步修改所有使用了该地址的代码,会增加开发的工作量。为此,Vue Router提供了命名路由

在定义路由匹配规则时,使用name属性为路由匹配规则定义路由名称,即可实现命名路由。当路由匹配规则有了路由名称后,在定义路由链接或执行某些跳转操作时,可以直接通过路由名称表示相应的路由,不再需要通过路由路径表示相应的路由。

使用命名路由的语法格式如下。

{ path: '路由路径', name: '路由名称', component: 组件 }

注意

命名路由的name属性值不能重复,必须保证是唯一的

<router-link>标签中使用命名路由时,需要动态绑定to属性的值为对象。当使用对象作为to属性的值时,to前面要加一个冒号,表示使用v-bind指令进行绑定。在对象中,通过name属性指定要跳转到的路由名称,使用params属性指定跳转时携带的路由参数,语法格式如下。

<router-link :to="{ name: 路由名称, params: { 参数名: 参数值 } }"></router-link>

使用命名路由实现单击Home组件的“跳转到MovieDetails组件”链接跳转到MovieDetails组件,并在页面中获取id

单击“首页”链接后的页面效果单击“跳转到MovieDetails组件”链接后的页面效果,如下图所示。​​​​​​​

编程式导航

Vue中,页面有两种导航方式,分别是声明式导航和编程式导航。其中,使用<router-link>标签定义导航链接的方式属于声明式导航。而编程式导航是先通过useRouter()函数获取全局路由实例,然后通过调用全局路由实例实现导航。

Vue Router提供了useRouter()函数,使用它可以获取全局路由实例,该全局路由实例中提供了常用的push()方法replace()方法go()方法,获取全局路由实例的示例代码如下。

1.push()方法

push()方法会向历史记录中添加一个新的记录,以编程方式导航到一个新的URL。当用户单击浏览器后退按钮时,会回到之前的URLpush()方法的参数可以是一个字符串路径,或者一个描述地址的对象,示例代码如下。

如果在参数的对象中提供了path,则params会被忽略。为了传递参数,需要提供路由的name或者手动拼接带有参数的path,示例代码如下。

使用push()方法实现单击Home组件的“跳转到MovieDetails组件”链接跳转到MovieDetails组件,并在页面中获取id

2.replace()方法

replace()方法与push()方法类似,都是以编程方式导航到一个新的URLreplace()方法在导航后不会向历史记录中添加新的记录,而是会替换历史记录中的当前记录。

在声明式导航中,为<router-link>标签添加replace属性也能实现与replace()方法类似的效果,示例代码如下。

// 编程式导航
router.replace({ path: '/user' })
<!-- 声明式导航 -->
<router-link :to="{ path: '/user' }" replace></router-link>

3.go()方法

go()方法用于实现前进或后退的效果,其参数表示历史记录中前进或后退的步数,类似于window.history.go(),相应的地址栏也会发生改变。

  • go(1)表示前进一条记录。
  • go(-1)表示后退一条记录。

使用go()方法实现单击MovieDetails组件的“后退”按钮后返回到Home组件的效果。

先单击“首页”链接切换到首页,然后单击“跳转到MovieDetails组件”,查看添加了“后退”按钮的页面效果,如下图所示。

导航守卫

导航守卫用于控制路由的访问权限。例如,访问后台主页时,需要用户处于已登录状态,如果没有登录,则跳转到登录页面。用户在登录页面进行登录操作,若登录成功,则跳转到后台主页;若登录失败,则返回登录页面。

登录功能中使用导航守卫的效果,如下图所示。

导航守卫主要分为全局导航守卫导航独享守卫组件导航守卫

​​​​​​​下面讲解全局导航守卫的定义与使用。

全局导航守卫会拦截每个路由规则,从而对每个路由进行访问权限的控制,定义全局导航守卫的示例代码如下。

每个全局导航守卫方法中接收3个形参:tofromnext

  • to:表示目标路由对象
  • from:表示当前导航正要离开的路由对象
  • next:next函数,如果不接收next()函数,则默认允许用户访问每一个路由;如果接收了next()函数,则必须调用next()函数,否则不允许用户访问任何一个路由。

注意

next()函数具有3种调用方式,分别为next()next(false)next('/'),其中,next()表示执行下一个钩子函数;next(false)表示强制停留在当前页面;next('/')表示跳转到其他地址。

使用全局导航守卫实现当进入MovieDetails组件时,判断当前用户是否登录,如果没有登录则跳转到登录页面,如果已登录则跳转到电影详情页面

先切换到首页,然后单击“跳转到MovieDetails组件”链接,会显示登录页面,说明全局导航守卫拦截成功,如下图所示。​​​​​​​​​​​​​​

相关推荐

  1. vue3

    2024-05-09 15:36:05       46 阅读
  2. Vue

    2024-05-09 15:36:05       39 阅读
  3. Vue

    2024-05-09 15:36:05       33 阅读
  4. <span style='color:red;'>Vue</span><span style='color:red;'>路</span><span style='color:red;'>由</span>

    Vue

    2024-05-09 15:36:05      28 阅读
  5. [Vue]

    2024-05-09 15:36:05       19 阅读
  6. vue-详解

    2024-05-09 15:36:05       17 阅读

最近更新

  1. TCP协议是安全的吗?

    2024-05-09 15:36:05       18 阅读
  2. 阿里云服务器执行yum,一直下载docker-ce-stable失败

    2024-05-09 15:36:05       19 阅读
  3. 【Python教程】压缩PDF文件大小

    2024-05-09 15:36:05       18 阅读
  4. 通过文章id递归查询所有评论(xml)

    2024-05-09 15:36:05       20 阅读

热门阅读

  1. redux实现原理

    2024-05-09 15:36:05       12 阅读
  2. 算法精讲:冒泡排序

    2024-05-09 15:36:05       12 阅读
  3. C++类型与声明

    2024-05-09 15:36:05       14 阅读
  4. 每天一个数据分析题(三百一十三)-漏斗模型

    2024-05-09 15:36:05       16 阅读
  5. var, let, const 的区别

    2024-05-09 15:36:05       12 阅读
  6. poker(typescript版)

    2024-05-09 15:36:05       13 阅读
  7. (六)Linux的Shell编程(下)

    2024-05-09 15:36:05       11 阅读