1. Vue Router介绍
Vue Router 是 Vue.js 官方的路由管理器。在 Vue.js 单页应用程序中实现客户端路由功能,通过将不同的 URL 映射到不同的组件,以实现页面之间的切换和导航。
Vue Router 的核心功能包括:
- 路由映射:Vue Router 允许您定义路由映射规则,将 URL 路径映射到 Vue 组件。通过使用路由映射,可以在 URL 改变时加载不同的组件,从而实现页面之间的切换。
- 嵌套路由:Vue Router 支持嵌套路由,允许您在父路由下定义子路由。这使得可以创建复杂的页面布局和嵌套组件结构,同时保持路由的层次性和可读性。
- 路由参数:可以在路由规则中定义参数,以捕获 URL 中的动态片段。这些参数可以作为路由组件的属性,用于动态地渲染组件内容。例如,可以定义一个带有商品ID参数的路由,以显示特定商品的详细信息。
- 路由导航:Vue Router 提供了导航守卫(Navigation Guards)功能,允许在路由切换前后执行相应的逻辑。可以在导航守卫中进行身份验证、权限检查或其他预处理逻辑,以决定是否允许用户访问或离开某个页面。
- 命名路由和命名视图:Vue Router 支持命名路由和命名视图,允许在路由规则和组件渲染时使用可读性更高的名称,而不是直接使用路径或组件名称。这可以提高代码的可维护性和可读性。
通过使用 Vue Router,可以实现单页应用程序的前端路由功能,构建交互式和流畅的用户界面。它与 Vue.js 框架无缝集成,并提供了丰富的路由管理功能,能够更轻松地管理应用程序的不同页面和导航逻辑。
官方地址:https://router.vuejs.org/zh/
2. 路由是什么
2.1. 计算机网络中的路由
路由是在计算机网络中,根据一定的规则和算法,将数据包从源节点传递到目标节点的过程。它是实现网络通信和数据传输的关键机制。
路由的工作原理是基于网络中的路由表(Routing Table)。路由表是一个存储在路由器或交换机中的数据结构,它记录了网络中各个目的地的可达路径和相关信息。根据路由表中的信息,路由器可以根据目标地址来选择下一个节点,并将数据包传递给适当的接口进行转发。
2.2. SPA是什么
SPA 是单页应用(Single-Page Application)的缩写,是一种 Web 应用程序的架构模式。在 SPA 中,整个应用程序只有一个 HTML 页面,该页面包含应用程序的骨架结构,而内容的变化和页面的切换是通过 JavaScript 动态地加载和更新的,而不是通过传统的多页应用中的页面刷新。
SPA 的特点包括:
- 单页面结构:SPA 只有一个初始的 HTML 页面,当用户与应用程序交互时,页面内容会动态地进行更新和切换,但浏览器不会重新加载整个页面。
- 前端路由:SPA 使用前端路由来管理页面的导航和切换。通过监听 URL 变化,SPA 可以根据不同的路由信息加载相应的组件或视图,实现页面间的无刷新切换。
- 异步加载:SPA 通过利用 AJAX、Fetch 或 WebSockets 等技术,可以异步地获取数据并更新页面内容,无需刷新整个页面。
- 更流畅的用户体验:由于 SPA 避免了页面的刷新,用户在与应用程序交互时会获得更快的响应速度和流畅的用户体验。
- 前后端分离:SPA 的前端与后端可以相对独立地开发和部署。前端负责处理用户界面和交互逻辑,而后端则负责提供数据接口和业务逻辑。
2.3. 前端路由
前端路由是一种在单页应用(SPA)中管理页面导航和视图切换的机制。前端路由通过在客户端内部维护一个路由器(router),根据 URL 的变化动态地加载不同的视图组件,实现页面的切换和导航,而无需重新加载整个页面。
简单的说就是:
- url与vue组件之间建立链接
- 用户点击了页面上的路由链接
- 前端路由把当前对应的组件渲染都浏览器中
3. 开始使用
3.1. 新建一个vue2项目
vue init webpack "router-vue2"
可以在创建项目的时候直接安装router,但是这个为了学习使用就先不安装,等后面再安装
3.2. Vue Router安装
Vue-router当前最新版本为4
Vue-router4 对应 Vue3中使用
Vue-router3 对应 Vue2中使用
这里使用vue2所以安装vue-router@3, 安装命令
npm i vue-router@3
3.3. 路由配置和使用
3.3.1. 在src文件夹下创建router/index.js文件
// 该页面用于创建整个应用的路由管理者router
import VueRouter from "vue-router";
// 应用VueRouter
Vue.use(VueRouter)
// 创建路由对象
const router = new VueRouter({
//路由规则
routes: [{},]
})
// 暴露一个router
export default router
3.3.2. 在main.js中配置路由
import Vue from 'vue'
import App from './App'
import router from './router/index.js'
Vue.config.productionTip = false
/* eslint-disable no-new */
new Vue({
render: h => h(App),
// 挂载到vue实例中
router
}).$mount('#app')
3.3.3. 新建两个页面
在src文件夹下新创建一个views文件夹,在views下创建Home.vue和My.vue
Home.vue
<template>
<div>
<h2>Home页面</h2>
</div>
</template>
<script>
export default {
}
</script>
<style scoped>
h2 {
text-align: center;
}
</style>
My.vue
<template>
<div>
<h2>My页面</h2>
</div>
</template>
<script>
export default {}
</script>
<style scoped>
h2 {
text-align: center;
}
</style>
3.3.4. 在router/index.js中配置路由规则
// 该页面用于创建整个应用的路由管理者router
import Vue from "vue";
import VueRouter from "vue-router";
//引入路由组件
import Home from '../views/Home.vue'
import My from '../views/My.vue'
// 应用VueRouter
Vue.use(VueRouter)
// 创建路由对象
const router = new VueRouter({
//路由规则
routes: [
//配置路由路径和路由组件
{
//这里的路径可自由定义
path: '/Home',
component: Home //要跳转到的组件 注意:这里不要加引号
},
{
path: '/My',
component: My //要跳转到的组件 注意:这里不要加引号
},
]
})
// 暴露一个router
export default router
3.3.5. 在组件中使用路由
在App.vue中使用
<template>
<div id="app">
<!-- 定义路由链接-->
<router-link to="/Home">首页</router-link>
<router-link to="/My">我的</router-link>
<hr/>
<!-- 定义路由占位符(指定位置展示路由组件)-->
<router-view/>
</div>
</template>
<script>
export default {
name: 'App',
components: {}
}
</script>
<style>
#app {
font-family: 'Avenir', Helvetica, Arial, sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
text-align: center;
color: #2c3e50;
margin-top: 60px;
}
</style>
3.3.6. 页面展示
4. 常用方法
4.1. 路由重定向
路由重定向指的是:用户在访问一个地址的时候,强制用户跳转到另一个地址 ,从而展示特定的组件页面。
通过路由规则的redirect属性,可以很方便地设置路由的重定向
很多网站刚进入的时候默认显示首页内容,就可以用这个
// 该页面用于创建整个应用的路由管理者router
import Vue from "vue";
import VueRouter from "vue-router";
//引入路由组件
import Home from '../views/Home.vue'
import My from '../views/My.vue'
// 应用VueRouter
Vue.use(VueRouter)
// 创建路由对象
const router = new VueRouter({
//路由规则
routes: [
{
path: '/',
redirect: '/Home' //重定向
},
//配置路由路径和路由组件
{
//这里的路径可自由定义
path: '/Home',
component: Home //要跳转到的组件 注意:这里不要加引号
},
{
//这里的路径可自由定义
path: '/My',
component: My //要跳转到的组件 注意:这里不要加引号
},
]
})
// 暴露一个router
export default router
4.2. 嵌套路由
新建两个TabA、TabB页面
TabA.vue
<template>
<h2>TabA页面</h2>
</template>
TabB.vue
<template>
<h2>TabB页面</h2>
</template>
router/index.js中配置嵌套路由
// 该页面用于创建整个应用的路由管理者router
import Vue from "vue";
import VueRouter from "vue-router";
//引入路由组件
import Home from '../views/Home.vue'
import My from '../views/My.vue'
import TabA from '../views/TabA.vue'
import TabB from '../views/TabB.vue'
// 应用VueRouter
Vue.use(VueRouter)
// 创建路由对象
const router = new VueRouter({
//路由规则
routes: [
{
path: '/',
redirect: '/Home' //重定向
},
//配置路由路径和路由组件
{
//这里的路径可自由定义
path: '/Home',
component: Home, //要跳转到的组件 注意:这里不要加引号
// 子路由(嵌套路由)
children: [
// 注意:子路由的 path 不需要加/
{path: 'TabA', component: TabA},
{path: 'TabB', component: TabB},
]
},
{
//这里的路径可自由定义
path: '/My',
component: My //要跳转到的组件 注意:这里不要加引号
},
]
})
// 暴露一个router
export default router
Home页面中使用
<template>
<div>
<h2>Home页面</h2>
<router-link to="/Home/TabA">TabA</router-link>
<router-link to="/Home/TabB">TabB</router-link>
<hr/>
<router-view/>
</div>
</template>
<script>
export default {
}
</script>
<style scoped>
h2 {
text-align: center;
}
</style>
页面展示
4.3. 路由传参
vue 路由传参的使用场景一般都是应用在父路由跳转到子路由时,携带参数跳转
有多种方式可以实现路由传参,以下是几种常见的方法:
4.3.1. params传参(路由路径参数Dynamic Route Matching)
在路由定义时,可以通过在路由路径中使用占位符来指定参数,并在路由组件中通过 $route.params 来获取传递的参数。
在 vue-router 中使用英文的冒号(:)来定义路由的参数项
TabA/:id 加参数id
// 该页面用于创建整个应用的路由管理者router
import Vue from "vue";
import VueRouter from "vue-router";
//引入路由组件
import Home from '../views/Home.vue'
import My from '../views/My.vue'
import TabA from '../views/TabA.vue'
import TabB from '../views/TabB.vue'
// 应用VueRouter
Vue.use(VueRouter)
// 创建路由对象
const router = new VueRouter({
//路由规则
routes: [
{
path: '/',
redirect: '/Home' //重定向
},
//配置路由路径和路由组件
{
//这里的路径可自由定义
path: '/Home',
component: Home, //要跳转到的组件 注意:这里不要加引号
// 子路由(嵌套路由)
children: [
// 注意:子路由的 path 不需要加/
{path: 'TabA/:id', component: TabA},
{path: 'TabB/:id', component: TabB},
]
},
{
//这里的路径可自由定义
path: '/My',
component: My //要跳转到的组件 注意:这里不要加引号
},
]
})
// 暴露一个router
export default router
Home中传参
<template>
<div>
<h2>Home页面</h2>
<router-link to="/Home/TabA/1">TabA</router-link>
<router-link to="/Home/TabB/2">TabB</router-link>
<hr/>
<router-view/>
</div>
</template>
<script>
export default {
}
</script>
<style scoped>
h2 {
text-align: center;
}
</style>
TabA中获取参数
<template>
<h2>TabA页面,id为:{{this.$route.params.id}}</h2>
</template>
<script>
export default {
}
</script>
页面显示
4.3.2. query传参(查询参数Query Parameters)
可以通过在路由路径中使用查询参数来传递数据,并在路由组件中通过 $route.query 来获取传递的参数
Home中根据query传参
<template>
<div>
<h2>Home页面</h2>
<router-link :to="{ path: '/Home/TabA', query: { id: '1' } }">TabA</router-link>
<router-link :to="{ path: '/Home/TabB', query: { id: '2' } }">TabB</router-link>
<hr/>
<router-view/>
</div>
</template>
<script>
export default {}
</script>
<style scoped>
h2 {
text-align: center;
}
</style>
在TabA中接收传参
<template>
<div>
<h2>TabA页面,id为:{{ this.$route.query.id }}</h2>
</div>
</template>
<script>
export default {
}
</script>
页面显示
4.3.3. meta传参(路由元信息Route Meta Fields)
可以在路由定义中添加元信息字段,用于传递自定义的参数或数据,并在路由组件中通过 $route.meta 来获取传递的数据
router/index.js中添加元信息字段(meta: {id: ‘123’})
// 该页面用于创建整个应用的路由管理者router
import Vue from "vue";
import VueRouter from "vue-router";
//引入路由组件
import Home from '../views/Home.vue'
import My from '../views/My.vue'
import TabA from '../views/TabA.vue'
import TabB from '../views/TabB.vue'
// 应用VueRouter
Vue.use(VueRouter)
// 创建路由对象
const router = new VueRouter({
//路由规则
routes: [
{
path: '/',
redirect: '/Home' //重定向
},
//配置路由路径和路由组件
{
//这里的路径可自由定义
path: '/Home',
component: Home, //要跳转到的组件 注意:这里不要加引号
// 子路由(嵌套路由)
children: [
// 注意:子路由的 path 不需要加/
{path: 'TabA', component: TabA, meta: {id: '123'}},
{path: 'TabB', component: TabB, meta: {id: '456'}},
]
},
{
//这里的路径可自由定义
path: '/My',
component: My //要跳转到的组件 注意:这里不要加引号
},
]
})
// 暴露一个router
export default router
Home页面
<template>
<div>
<h2>Home页面</h2>
<router-link :to="{ path: '/Home/TabA' }">TabA</router-link>
<router-link :to="{ path: '/Home/TabB' }">TabB</router-link>
<hr/>
<router-view/>
</div>
</template>
<script>
export default {}
</script>
<style scoped>
h2 {
text-align: center;
}
</style>
TabA页面接收
<template>
<div>
<h2>TabA页面,id为:{{ this.$route.meta.id }}</h2>
</div>
</template>
<script>
export default {
}
</script>
页面展示
5. 编程式导航和声明式导航
Vue Router提供了两种方式来进行导航:编程式导航和声明式导航
5.1. 编程式导航
编程式导航是通过在JavaScript代码中直接调用Vue Router的API来实现导航。你可以使用编程式导航来在组件中进行路由跳转、重定向或者前进/后退操作。以下是一些常见的编程式导航方法:
5.1.1. router.push(location):跳转到一个新的URL
<template>
<div>
<h2>Home页面</h2>
<button @click="goTabA">跳转到TabA</button>
<hr/>
<router-view/>
</div>
</template>
<script>
export default {
methods: {
goTabA() {
this.$router.push({ path: '/Home/TabA'});
}
}
}
</script>
<style scoped>
h2 {
text-align: center;
}
</style>
页面展示
5.1.2. router.replace(location):替换当前的URL,而不会在历史记录中创建新的记录。
<template>
<div>
<h2>Home页面</h2>
<button @click="goTabA">跳转到TabA</button>
<hr/>
<router-view/>
</div>
</template>
<script>
export default {
methods: {
goTabA() {
this.$router.replace({ path: '/Home/TabA'});
}
}
}
</script>
<style scoped>
h2 {
text-align: center;
}
</style>
页面展示
5.1.3. router.go(n):在历史记录中向前或向后移动多少步。
Home跳转到TabA
<template>
<div>
<h2>Home页面</h2>
<button @click="goTabA">跳转到TabA</button>
<hr/>
<router-view/>
</div>
</template>
<script>
export default {
methods: {
goTabA() {
this.$router.push({ path: '/Home/TabA'});
}
}
}
</script>
<style scoped>
h2 {
text-align: center;
}
</style>
TabA返回到Home
<template>
<div>
<h2>TabA页面</h2>
<button @click="goBack">跳转到TabA</button>
</div>
</template>
<script>
export default {
methods: {
goBack() {
this.$router.go(-1);
}
}
}
</script>
页面展示
5.1.4. router.back():后退一步,等同于 router.go(-1)。
5.1.5. router.forward():前进一步,等同于 router.go(1)。
back、forward效果与go一样就不展示了
5.2. 声明式导航
声明式导航是通过在模板中使用Vue Router提供的指令来实现导航。你可以在模板中使用组件来生成导航链接,它会自动渲染为一个带有正确URL的超链接。当用户点击链接时,Vue Router会自动处理导航。
是一个用于生成路由链接的组件。它会自动渲染成一个 标签,并在点击时触发路由的导航。你可以通过指定 to 属性来设置要导航到的目标路由。
以下是一个使用声明式导航的示例:
<template>
<div>
<h2>Home页面</h2>
<router-link to="/Home/TabA">TabA</router-link>
<router-link to="/Home/TabB">TabB</router-link>
<hr/>
<router-view/>
</div>
</template>
<script>
export default {
}
</script>
<style scoped>
h2 {
text-align: center;
}
</style>
在上面的示例中,当用户点击"TabA"或"TabB"链接时,Vue Router会自动导航到相应的路由路径。
编程式导航和声明式导航在不同的场景下有不同的用途。
编程式导航通常用于在组件中通过JavaScript代码进行导航,例如在事件处理程序或生命周期钩子中进行动态导航,而声明式导航则更适合在模板中静态地生成导航链接。
6. 导航守卫
导航守卫是一组用于控制路由导航的钩子函数。这些钩子函数允许你在路由导航过程中进行拦截和控制,以实现诸如身份验证、权限检查、页面保护等功能。
Vue Router提供了三种类型的导航守卫钩子:
6.1. 全局守卫
在整个应用程序的路由导航过程中都会触发的钩子函数。包括以下钩子函数:
- beforeEach(to, from, next):在每个导航触发之前调用,可以用于进行全局的身份验证、权限检查等。
- beforeResolve(to, from, next):在每个导航被确认之前调用,可以用于处理异步路由组件的加载。
- afterEach(to, from):在每个导航成功完成后调用,可以用于执行一些全局的操作,如页面滚动、统计等。
beforeEach****的回调函数中接收 3 个形参
- to:即将进入的路由Route对象;
- from:即将离开的路由Route对象;
- next是一个函数,调用next()表示放行, 允许这次路由跳转
next 函数的 3 种调用方式
实际案例中当用户访问后台系统主页时可能遇到如下情况
- 当前用户拥有后台主页的访问权限,直接放行:next()
- 当前用户没有后台主页的访问权限,强制其跳转到登录页面:next(‘/login’)
- 当前用户没有后台主页的访问权限,不允许跳转到后台主页:next(false)
router.beforeEach((to, from, next) => {
//to 要访问的路径
//from 代表从哪个路径跳转而来
// next 是函数,表示放行
// next() 放行
// next('/*') 强制跳转
const user = window.sessionStorage.getItem('user')
if (to.path === '/Login') {
return next();
}
if (!user) {
return next('/Login')
}
if (to.path === '/' && user) {
return next('/home')
}
next()
})
6.2. 路由独享守卫
仅在特定路由配置中定义的钩子函数,可以在路由配置对象中使用beforeEnter来定义该钩子函数。
用法与全局守卫大同小异,独享路由守卫是没有后置路由守卫的
6.3. 组件内守卫
在路由组件内定义的钩子函数。包括以下钩子函数:
- beforeRouteEnter(to, from, next):在路由进入组件之前调用,可以在此钩子函数中访问组件实例之前的this上下文。
- beforeRouteUpdate(to, from, next):在当前路由复用组件时调用,但是参数发生变化时触发。
- beforeRouteLeave(to, from, next):在离开当前路由时调用,可以在此钩子函数中进行页面离开前的确认或者保存数据。
7. hash和history模式
路由有两种工作模式,分别是:hash 和 history,默认的就是 hash 的工作模式
7.1. hash模式
- url中# 就是代表 hash ,后面就是 hash 值
- 在hash模式下,URL中的哈希值(即#后面的部分)用于表示路由路径。例如,http://localhost:8080/#/Home/TabA
- 哈希值的变化不会触发浏览器向服务器发送请求,而是在前端进行处理。
- Vue Router通过监听hashchange事件来捕获哈希值的变化,并根据哈希值来进行路由的匹配和渲染。
7.2. history模式
history需要配置mode项:mode: ‘history’,
// 该页面用于创建整个应用的路由管理者router
import Vue from "vue";
import VueRouter from "vue-router";
//引入路由组件
import Home from '../views/Home.vue'
import My from '../views/My.vue'
import TabA from '../views/TabA.vue'
import TabB from '../views/TabB.vue'
// 应用VueRouter
Vue.use(VueRouter)
// 创建路由对象
const router = new VueRouter({
mode: 'history',
//路由规则
routes: [
{
path: '/',
redirect: '/Home' //重定向
},
//配置路由路径和路由组件
{
//这里的路径可自由定义
path: '/Home',
component: Home, //要跳转到的组件 注意:这里不要加引号
// 子路由(嵌套路由)
children: [
// 注意:子路由的 path 不需要加/
{path: 'TabA', component: TabA, meta: {id: '123'}},
{path: 'TabB', component: TabB, meta: {id: '456'}},
]
},
{
//这里的路径可自由定义
path: '/My',
component: My //要跳转到的组件 注意:这里不要加引号
},
]
})
// 暴露一个router
export default router
- 在history模式下,URL中的路径表示实际的路由路径。例如,http://localhost:8080/Home/TabA
- history模式依赖于HTML5 History API,它允许前端控制浏览器的历史记录。
- 当路由切换时,history模式会使用pushState方法将新的URL添加到浏览器的历史记录中,而不会触发页面的刷新。
- 服务器端需要正确配置,以便在接收到这些URL时返回正确的页面内容。
7.3. hash和history模式区别
7.3.1. URL格式
hash模式:URL中包含一个哈希值(#),例如:http://localhost:8080/Home#/Home/TabA
history模式:URL中不包含哈希值,使用真实的URL路径,例如:http://localhost:8080/Home/TabA
7.3.2. 兼容性
hash模式:对于较低版本的浏览器,包括一些旧版的IE浏览器,都很好地支持hash模式。
history模式:需要服务器端的配置支持。在不支持HTML5 History API的环境中,会自动回退到hash模式。
7.3.3. URL美观性
hash模式:URL中的哈希值对于前端路由来说是一个片段标识符,不会发送到服务器端。因此,即使URL发生变化,页面也不会重新加载,但会触发前端路由的变化。
history模式:URL中的路径是真实的URL路径,可以直接发送到服务器端。当导航到一个新的URL时,页面会向服务器发送请求,并且服务器需要正确配置以返回对应的页面。
7.3.4. 历史记录
hash模式:每次路由切换时,哈希值会被添加到浏览器的历史记录中,因此可以通过浏览器的前进和后退按钮进行导航。
history模式:使用HTML5 History API,路由切换时会修改浏览器的URL,但不会添加额外的历史记录。因此,通过浏览器的前进和后退按钮进行导航会触发真实的页面加载。