过了一遍vue2的router,整理一下小结
目录
一、前端路由的概念与原理
1.1 什么是路由
1.2 路由的工作方式
二、vue-router的基本使用
2.1 安装、配置、使用router
2.2 redirect重定向
三、嵌套路由
3.1 声明子路由的规则
3.2 默认子路由
四、动态路由
4.1 动态路由的概念
4.2 动态路由取参方式一(:参数项)
4.3 动态路由取参方式二(props传参)– 常用
4.3 动态路由 – query & fullPath
query传参取值
五、编程式导航跳转
5.1 声明式导航 & 编程式导航
5.2 vue-router中的编程式导航API
六、导航守卫
6.1 什么是导航守卫
6.2 全局 前置 守卫
6.3 守卫方法的3个形参
6.4 next() 的三个调用方式
6.5 控制访问权限
一、前端路由的概念与原理
1.1 什么是路由
路由(router)就是 对应关系
地址与页面上组件的对应关系
不同的地址展示不同的组件
路由就是:Hash地址 与 组件 之间的 对应关系
1.2 路由的工作方式
1、用户 点击了 页面上的 路由链接 (本质上是a链接)
2、导致了 URL地址栏 中的 Hash值 发生了变化
3、前端路由监听到了Hash地址的变化
4、前端路由把当前 Hash地址对应的组件 渲染到浏览器中
二、vue-router的基本使用
2.1 安装、配置、使用router
1、安装vue-router包
npm i vue-router@3.5.2 -S
此时,package.json里多出路由安装,后面是版本号
"vue-router": "^3.5.2"
2、创建路由模块
在src源代码目录下,创建 router/index.js 路由模块,并进行配置
// src/router/index.js文件就是当前项目的路由模块// 路由模块的配置有四部//1、导入Vue 和 VueRouter 的包import Vue from 'vue'import VueRouterfrom 'vue-router'//2、调用 Vue.use()函数,把VueRouter安装为Vue项目的插件//在Vue里面装插件,调用 use()函数Vue.use(VueRouter) //3、创建路由的实例对象const router = new VueRouter()//4、向外共享路由的实例对象export default router
这个时候,去main.js文件上,把router挂载到Vue实例上(router被共享了)
//导入 routerimport router from './router' /*注意:在模块化导入的时候,如果给定的不是具体的文件(是文件夹)则默认导入这个文件夹下,名字叫 index.js 的文件而且,router目录是拿来配置路由的,所以里面只需要创建一个index.js文件所以可以不用写全为:import router from './router/index.js'*///在Vue实例上挂载路由new Vue({render: h => h(App),router}).$mount('#app')---------------------/*因为路由导入的时候,取的名字是router,和实例里面的router属性名同名,所以可以简写为一个router如果是这么导入的话import href from './router'在实例上就需要这么挂载new Vue({render: h => h(App),router:href}).$mount('#app')*/
当配置结束以后
3、导入并挂载路由模块
在router/index.js(路由模块)中声明组件路由
//1、导入需要声明成路由的组件//导入路由需要的组件import Home from '@/components/Home.vue'import Movie from '@/components/Movie.vue'import About from '@/components/About.vue'//2、在Vue实例内绑定路由和hash的对应关系const router = new VueRouter({//在路由的实例对象中//用一个 routes:[]数组,来定义 hash地址与组件之间的对应关系routes:[{path:'/', //path指的是路由的hash地址,跳转的时候用这个路径跳转到对应组件,如果path只给了一个 /,则是首页默认展示component:Home //要展示的组件},{path:'/movie',component:Movie},{path:'/About',component:About}]})
这个时候,组件的路由就配置完成了!
在App组件里面,用router-view去展示组件即可
4、声明 路由链接 和 占位符
只要在项目中安排和配置了 vue-router
就可以使用 router-view 组件
占位符:
作用:给路由组件进行占位,组件的路由进行切换的时候,组件会在这个地方进行展示
路由链接:
当安装配置了router,就可以使用router-link来替代普通的a链接进行跳转
首页电影关于首页电影关于
router-link中的 to属性,与a链接中的href属性相同,都是用来填写跳转的路径链接
router-link的to属性中的属性值,不需要写成 #/path,直接忽略#号,用/开头即可
2.2 redirect重定向
路由重定向 指的是: 用户在访问 地址A 的时候,强制用户跳转 到地址C,从而展示特定的组件页面。
通过路由规则的redirect属性,指定一个新的路由地址为 /,然后通过redirect重定向指向一个组件路由
//3、创建路由的实例对象const router = new VueRouter({//在路由的实例对象中//用一个 routes:[]数组,来定义 hash地址与组件之间的对应关系routes:[{path:'/',redirect:'/Home'},{path:'/Home', component:Home },{path:'/Movie',component:Movie},{path:'/About',component:About}]})
就是首次打开页面的时候,url访问的是 端口号/#/
但是没有组件声明的path路径是 /
所以打开页面没有进行路由跳转时候view是空白滴,所以就是打开的时候,/路径强制跳转到指定的组件路由路径
三、嵌套路由
1、模板内容中又有 子级路由链接
2、点击 子级路由链接 显示 子级模板内容
其实就是在App组件里面展示出来的路由组件内又绑定了其他的路由
3.1 声明子路由的规则
通过 children 属性声明 子路由规则
在index.js文件的路由实例中,在已声明的路由内,用children属性,以数组对象的形式,去声明在这个组件路由内的子路由规则。
举例
routes:[{path:'/About',component:About,children:[{path:'tab1',component:Tab1},{path:'tab2',component:Tab2},]}]})
注意:外层的路由的path属性值是有斜杠/开头的,其下的子路由是不用写/斜杠开头
子路由在该父路由内调用router-link和view即可
在父路由内嵌套link子路由的时候,需要在前面加上父路由的链接/父级/子级
3.2 默认子路由
在绑定了子路由以后,想要实现打开的时候,就默认展示某个子路由
方法:给父级路由重定向redirect:/父路由/子路由
默认子路由:如果children数组中,某个路由规则的Path值为空字符串,则这条路由规则叫做子路由
{path:'/About',component:About,children:[{path:'', //tab1的path为空,一进入About默认展示tab1component:Tab1},{path:'tab2',component:Tab2}
四、动态路由
4.1 动态路由的概念
动态路由指的是:把 hash地址中 可变的部分 定义为 参数项,从而 提高路由规则的复用性
(也就是说路由的path属性值是固定的,hash/(可变的部分),地址后面的可变的部分
在router中使用 英文的冒号( : ),来定义路由的参数项,如下
{path:'/Movie',component:Movie} //这里是访问Movie
但是,要访问Movie下的id值,就用 :参数项
{path:'/Movie/:id',component:Movie},
id作为一个动态传入的参数项
4.2 动态路由取参方式一(:参数项)
举例
在router的配置项中,给Movie的组件路由添加一个动态的id参数项,然后在访问该路由的时候,通过不同的id去访问到不同的数据
1、给Movie的配置项添加参数项
{path:'/Movie/:id',component:Movie},
2、给路由绑定链接,并传id值,希望通过id值来访问到不同电影的数据
大电影中电影小电影
3、此时如何通过Movie去获取到传递过来的id
打开Movie组件,当点击跳转传递了id后,测试打印组件的this
log出来的this是Movie组件的实例,打开找到一个 $route (不带r的) 的属性,指向的是一个object
其中有一个params对象,其中包含了一个id属性(这个id就是在路由path上定义的动态参数项id)
取值: this.$route.params.参数项
(其中this是可以省去不写的))
4.3 动态路由取参方式二(props传参)– 常用
(两种取参方式彼此独立)
该取参方法:给路由规则开启props传参
1、给组件添加一个 props:[],与methods和data平级
export default {name: 'Movie',props:[],methods:{showThis(){console.log(this);}}}
2、回到router/index的路由实例中,为该组件的路由添加props,并把值设置为true,表示为该路由开启props传参
{path:'/Movie/:id',component:Movie,props:true},
这里动态传了一个参数项id,然后开启props传值
3、回到Movie组件,在props数组中获取到参数值
props:['id'],
4、打印测试取值是否成功
//在结构上直接调用参数项id{{id}}
//在行为上则是 this.参数项methods:{showThis(){// console.log(this);console.log(this.id);}}
4.3 动态路由 – query & fullPath
query传参取值
除了路径参数以外,还有查询参数
在hash地址中,在后面拼接 ” /> this.$route.query 来访问查询参数
大电影中电影小电影
这样子写,参数之间中间没有空格,属性值没有引号
然后去看组件的this,可以在route对象中找到query的属性
如果要获取到它的值,就是:this.$route.query
fullPath
当打开this,发现route对象上除了query和params以外还有一个fullPath和path
两者的区别:path不包含查询参数,fullPath包含了路径和查询参数,是一个完整的hash地址
如果需要用到完整路径,就是fullPath,不需要用到参数,就是path
五、编程式导航跳转
编程式导航跳转: push、replace、go
5.1 声明式导航 & 编程式导航
声明式导航:
在浏览器中,点击链接 实现导航的方式,叫做 声明式导航,例如:
普通网页中点击 链接,vue项目中点击 都属于声明式导航
就是声明一个标签来进行跳转
编程式导航
在浏览器中,调用js – API方法 实现导航的方式,叫做 编程式导航,例如:
普
5.2 vue-router中的编程式导航API
vue中最常用的编程式导航跳转: push、replace、go
this.$router.push(“hash地址”)
跳转到指定的hash地址,并 增加 一条历史记录
this.$router.replace(“hash地址”)
跳转到指定的hash地址,并 替换当前的 历史记录
this.$router.go(数值n)
n值可为负数和正数
让当前页面前进/后退n步
前进为+n
后退为-n
注意:如果后退的层数超过上限(-100等),则页面原地不动
$router.go的简化用法
在实际操作中,一般只会前进和后退一层页,因此vue-router提供了两个便捷方法
$router.back()
在历史记录中,页面后退一层
*$router.forward()
在历史记录中,页面前进一层
这种操作,只需要写在行内就可以了
给后退按钮绑定点击事件,然后方法直接书写
六、导航守卫
6.1 什么是导航守卫
导航守卫 可以 控制路由的访问权限
例如:
在首页,点击导航进入后台主页,需求是在用户登录账号以后才可访问
但是,在未登录的情况下,是可以直接访问到Main后台主页的
就需要通过导航守卫来控制是否可以跳转
如果没有登录,访问main主页的话,就会强制跳转到登录页面
6.2 全局 前置 守卫
前置:从A跳到B的时候,还没有跳呢,就触发了前置导航守卫
每次发生路由的 导航跳转 时,都会触发 全局前置守卫,因此,在全局前置守卫中,可以对每个路由进行 访问权限 的控制:
声明全局前置守卫的方法
调用路由实例对象的 beforeEach 方法,即可声明:全局前置守卫
每次发生路由导航跳转的时候,都会自动触发 beforeEach(方法内的回调函数fn)这个fn回调函数
(在路由模块声名语法)
//调用 router.beforeEach()方法声明全局前置守卫router.beforeEach(fn)
beforeEach:在xxx之前
举例
//调用 router.beforeEach()方法声明全局前置守卫router.beforeEach(function(){})
这个fn回调就是守卫方法,只要发生了路由的跳转,必然会触发这个fn回调
6.3 守卫方法的3个形参
全局前置守卫 的回调函数中接收了3个形参,格式为:
router.beforeEach(function(to,from,next){})
三个形参:(从A跳转到B)
1、to:将要访问的路由的信息对象 (B方)
2、from:是将要离开的路由的信息对象(也就是A方)
3、next:是一个函数,调用 next() 表示旅行,允许本次路由导航,如果在fn里面不写 next(),那么全部的路由都不会实现跳转(因为在路由执行之前,先触发了fn回调,然后没有被放行)
6.4 next() 的三个调用方式
一、当前用户 拥有 后台主页的访问权限,直接放行:next()
二、当前用户 没有 后台主页的访问权限,强制跳转到指定(登录)页面: next(‘/login’)
三、当前用户 没有 后台主页的访问权限,不允许发生跳转,强制用户停留在当前页面(不给跳到后台主页):next(false)
6.5 控制访问权限
以上图举例实现
前置准备
1、创建两个组件:Main和Login,并为其添加路由规则
{ path:'/login',component:Login }, { path:'/Main',component:Main }
2、然后给一个HOME主页去绑定后台主页的路由
访问后台主页
3、这个时候在主页点击,是可以直接跳转到路由滴
问题:这个时候是没有登录滴,就需要进行控制
写法
在路由模块内声明前置守卫,但是不能直接放行,需要通过if去控制是否放行
分析:
1、要拿到用户将要访问的 hash 地址
2、判断 hash 地址是否等于 /main
2.1 如果等于 /main,说明需要登录之后才可以访问成功!
2.2 如果不等于 /main,就表示不需要登录,直接放行:next()
3、如果访问的地址是 /main,则需要读取 localStorage 中的 token 值
通过 localStoragec.getItem(‘token’)来获取到token值
(当用户第一次使用账号密码成功进行登录后,服务器便生成一个Token,所谓的Token,其实就是服务端生成的一串加密字符串、以作客户端进行请求的一个“令牌”)
3.1 如果有token,则放行
3.2 如果没有token,则强制跳转到/login 登录页
//调用 router.beforeEach()方法声明全局前置守卫router.beforeEach(function(to,from,next){console.log(to);console.log(from);if(to.path === '/Main'){//1、访问后台主页,需要判断后台是否有tokenconst token = localStorage.getItem('token')//3、如果token值存在,就表示已经登录if(token){next()}else{//4、没有登录,强制跳转到Login登录页next('/Login')}}else{//2、如果访问的不是后台,就直接放行了next()}})