前端路由和vue-router
1. 前端路由的概念与原理
1.1 什么是路由
路由 Router 就是对应关系
1.2 SPA 与前端路由
SPA:
SPA 指的是一个 web 网站只有唯一的一个 HTML 页面,所有的组件的展示与切换都在这唯一的一个页面内完成。此时,不同的组件之间的切换需要通过前端路由来实现。
前端路由:
Hash 地址 与 组件之间的对应关系
1.3 锚链接
- 页面不会刷新
- 会导致浏览历史
location.hash
可访问到当前hash 地址
location.href
可访问到当前全部地址
1.4 前端路由工作方式
- 用户点击了页面上的路由链接
- 导致了 URL 地址栏中的 Hash 值发生变化
- 前端路由监听到了 Hash 地址的变化
- 前端路由把当前 Hash 地址对应的组件渲染到浏览器中
1.5 手动模拟简易的前端路由
-
通过动态组件
<component>
,指定当前渲染的组件 -
通过监听
window.onhashchange
事件,当hash 地址发生变化,会触发当前事件 -
通过
location.hash
访问到当前hash 地址,转存到data节点的 comName变量下 -
comName 变量是字符串,是动态组件
<component>
的is
属性值,默认为 Left -
当 App 根组件一被创建就监听
window.onhashchange
事件,在 created 声明周期
案例源码:
App.vue
<template>
<div class="outer">
<div class="text-box">
<h1> App.vue 根组件</h1>
<a href="#/left">Left</a>
<a href="#/right">Right</a>
</div>
<hr>
<component :is="comName"></component>
</div>
</template>
<script>
// 1.导入需要使用的 Vue 组件
import Left from '@/components/Left.vue'
import Right from '@/components/Right.vue'
// 默认导出 固定写法
export default {
components: {
Left,
Right,
},
data() {
return {
// 在动态组件的位置要展示的组件的名字
comName: 'Left'
}
},
created(){
// 只要当前的组件被创建
// 就监听 window 对象的 onhashchange 事件
window.onhashchange = () => {
// 箭头函数里面的 this 与外面的this 保持一致
console.log('监听到了 hash 的变化:' , location.hash)
if(location.hash === '#/left'){
this.comName = 'Left'
}else{
this.comName = 'Right'
}
}
}
}
</script>
<style lang="less">
.text-box{
background-color: pink;
h3 {
color: blue;
}
a{
margin-left: 20px;
}
}
.outer{
background-color: rgb(240, 243, 242);
padding: 20px;
}
</style>
Left.vue
<template>
<div class="left-box">
<h3 >Left 组件</h3>
</div>
</template>
<script></script>
<style >
.left-box{
background-color: rgb(135, 173, 216);
min-height: 200px;
}
</style>
Right.vue
<template>
<div class="right-box" >
<h3>Right 组件</h3>
</div>
</template>
<script></script>
<style lang="less" scoped>
.right-box{
background-color: rgb(146, 228, 194);
min-height: 200px;
}
</style>
2. vue-router 的基本用法
2.1 什么是 vue-router
vue-router 是 vue.js 官方给出的 路由解决方案 。它只能结合 vue 项目进行使用,能够轻松的管理 SPA 项目中组件的切换。
2.2 安装配置以及基本使用
-
安装 vue-router 包
在 vue 2 的项目中,安装 vue-router 的命令如下:
npm i vue-router@3.5.2 -S
-
创建路由模块
在
src
源代码目录下,新建router/index.js
路由模块,并初始化如下代码:// 1. 导入 Vue VueRouter import Vue from 'vue' import VueRouter from 'vue-router' // 2. 调用 Vue.use() 函数,把VueRouter 安装为 Vue 的插件 // 在 vue 中安装插件都是使用其 use 方法 Vue.use(VueRouter) // 3. 创建路由实例对象 const router = new VueRouter() // 4. 向外共享路由的实例对象 export default router
-
导入并挂载路由模块
在
main.js
入口文件中导入并且挂载import Vue from 'vue' import App from './App.vue' // 1.导入路由模块 拿到路由实例对象 import router from '@/router//index.js' new Vue({ render: h => h(App), // 2.在 vue 项目中,挂载路由 router: router }).$mount('#app')
-
声明路由链接和占位符
在
App.vue
中声明链接和占位符使用
router-link
链接代替普通的 a 链接- 标签名不一样
to
代替 href- hash地址不用加
#
- 之后浏览器渲染页面会渲染为 a 链接
<div class="outer"> <div class="text-box"> <h1> App.vue 根组件</h1> <!-- <a href="#/left">Left</a> <a href="#/right">Right</a> --> <router-link to="/left">Left</router-link> <router-link to="/right">Right</router-link> </div> <hr> <!-- 在项目中安装配置了 vue-router,就可以使用 router-view 这个组件 --> <!-- 作用:占位符 给组件占位 --> <router-view></router-view> </div>
在 路由模块
index.js
中添加路由规则// 1. 导入 Vue VueRouter import Vue from 'vue' import VueRouter from 'vue-router' // 导入需要的组件 import Left from '@/components/Left.vue' import Right from '@/components/Right.vue' // 2. 调用 Vue.use() 函数,把VueRouter 安装为 Vue 的插件 // 在 vue 中安装插件都是使用其 use 方法 Vue.use(VueRouter) // 3. 创建路由实例对象 const router = new VueRouter({ // routes 是一个数组 // 作用:定义 hash 地址 与 组件 之间的对应关系 routes:[ {path: '/left', component: Left}, {path: '/right', component: Right}, ] }) // 4. 向外共享路由的实例对象 export default router
注意点:在 模块化导入 的时候,如果给定的是文件夹,则默认导入这个文件夹下的 index.js 的文件
3. vue-router 常见用法
3.1 路由重定向
路由重定向指的是:用户在访问地址A的时候,强制用户跳转到地址C,从而展示特定的组件页面。通过路由规则的 redirect 属性,指定一个新的路由地址,可以很方便地设置路由的重定向。
const router = new VueRouter({
// routes 是一个数组
// 作用:定义 hash 地址 与 组件 之间的对应关系
routes:[
// 当用户访问的是 / 重定向到 /left
{path: '/', redirect: '/left'},
// 路由规则
{path: '/left', component: Left},
{path: '/right', component: Right},
]
})
3.2 嵌套路由
通过路由实现组件的嵌套显示,叫做嵌套路由。
-
在 Right.vue 中声明子级路由链接和路由占位符
<!-- 子级路由链接 --> <router-link to="/right/tab1">Tab1</router-link> <router-link to="/right/tab2">Tab2</router-link> <hr> <!-- 子级路由占位符 --> <router-view></router-view>
-
在
src/router/index.js
模块中,导入需要的组件,并使用children
属性声明子路由规则:import Tab1 from '@/components/Tab1.vue' import Tab2 from '@/components/Tab2.vue' const router = new VueRouter({ // routes 是一个数组 // 作用:定义 hash 地址 与 组件 之间的对应关系 routes:[ // 当用户访问的是 / 重定向到 /left {path: '/', redirect: '/left'}, // 路由规则 {path: '/left', component: Left}, { path: '/right', component: Right, redirect: '/right/tab1', children: [ // 子路由规则 {path: 'tab1', component: Tab1}, {path: 'tab2', component: Tab2}, ] }, ] })
3.3 默认子路由
如果 children 数组中某个路由规则的 path 值为空字符串,则这条路由规则叫做 默认子路由
children: [
// 默认子路由
{path: '', component: Tab1},
// 子路由规则
{path: 'tab1', component: Tab1},
{path: 'tab2', component: Tab2},
]
3.3 动态路由匹配
3.3.1 动态路由的概念
动态路由指的是:把 Hash 地址中可变的部分定义为参数项,从而提高路由规则的复用性。在 vue-router 中使用英文的冒号 :
来定义路由的参数项。
{path: '/left/:id', component: Left}
{path: '/left/1', component: Left},
{path: '/left/2', component: Left},
{path: '/left/3', component: Left},
如何拿到参数项有下面两种: 3.3.2 和 3.3.3
3.3.2 参数对象 参数值
this.$route
是路由的参数对象- 可以在组件中通过
this.$route.params.xxx
访问到路由 path 传递的参数xxx
,其中 this 可以省略,可以写成$route.params.id
this.$routr
是路由的导航对象
3.3.3 为路由开启 props 传参
index.js
中为路由规则 props 传参,从而方便的拿到动态参数的值
{path: '/left/:id', component: Left , props: true},
Left.vue
使用props 接收
props: ['id']
3.3.4 拓展 query 和 fullPath
-
在 hash 地址中,
/
后面的参数项,叫做 路径参数在路由参数对象中,需要使用
this.$route.params
来访问路径参数 -
在 hash 地址中 ,
?
后面的参数项,叫做 查询参数在路由参数对象中,需要使用
this.$route.query
来访问查询参数 -
this.$route.path
是路径部分,如/left/2
-
this.$route.fullPath
是完整的地址,如/left/2?name=zs&age=30
3.4 编程式导航跳转
3.4.1 声明式导航和编程式导航
-
在浏览器中,点击链接实现导航的方式,叫做声明式导航
如:普通网页的
<a>
链接,vue 项目的<router-link>
-
在浏览器中,通过 API 方法实现导航的方式,叫做编程式导航
普通网页中调用
location.href
跳转到新页面的方式
3.4.1 常用 vue-router 中的编程式导航 API
this.$router
是导航对象
下面的代码在标签行内书写必须省略 this,否则报错
-
this.$router.push('hash 地址')
跳转到指定的 hash 地址,并增加一条历史记录
-
this.$router.replace('hash 地址')
跳转到指定的 hash 地址,并替换掉当前的历史记录
-
this.$router.go(数值 n)
- 可以在浏览历史中前进和后退
- 负数代表后退,负数代表前进
-
this.$router.back()
后退一步 -
this.$router.forward()
前进一步
3.5 导航守卫
3.5.1 概念
导航守卫可以控制路由的访问权限。
3.5.2 全局前置守卫
每次发生路由的 导航跳转 时,都会 触发全局前置守卫 。因此,在全局前置守卫中,程序员可以对每个路由 进行访问权限的控制 。
- 调用路由实例对象的
beforeEach
方法,即可声明 " 全局前置守卫 " - 每次发生路由导航跳转的时候,都会自动触发 callback 这个回调函数
const router = new VueRouter({...})
// 全局守卫导航
// 只要发生了路由跳转 必然触发beforeEach中的回调函数
router.beforeEach(callback)
3.5.3 回调函数的3个形参
to
是将要访问的路由的信息对象from
是将要离开的路由对象的信息next
是一个函数 调用next()
表示放行,允许这次路由导航
const router = new VueRouter({...})
router.beforeEach((to, from, next) => {
//code...
})
3.5.4 next 函数的 3 种调用方式
3.5.5 控制访问权限 - 小案例
等于情况下可以访问 /main
到达主页,未登录情况下强制跳转到 /login
登录页面
<router-link to="/main">main 主页</router-link>
router.beforeEach((to, from, next) => {
// 1.拿到将要访问的 hash 地址
// 2.判断 hash 地址是不是 /main
// 3.如果等于 读取 localStorage 中的 token 有则放行,无则跳转 /login
// 4.如果不等于 直接放行
if(to.path === '/main'){
const token = localStorage.getItem('token')
if(token){
next()
} else {
next('/login')
}
} else {
next()
}
})