前端路由的概念与原理
1. URL:
1.1 什么是URL?
URL(Uniform Resource Locator,统一资源定位符)用于定位网络上的资源
1.2 URL的组成部分?
格式:协议://主机号 : 端口号/路径 ? 参数
示例:https://www.euphoria:8083/images/cat.png?name=ls#abc
1.3 Hash:
- “#” 号后面的部分,专业术语为 “Hash地址”
- Hash 地址发生变化,
不会导致浏览器页面的刷新
- Hash 地址发生变化,
会形成浏览器历史记录
- vue 就是基于 hash 的这些特性来做路由的跳转,实现页面切换
2. 应用类型与路由的概念:
多页应用与后台路由:多页应用中,想要切换页面就是跳转到一个新的 html 页面,路由工作是由后端完成的
单页应用与前端路由:只有唯一的一个 HTML 页面,想要
切换页面只能切换组件
,这种切换组件达到页面切换的效果,就是前端路由
前端路由:访问不同的 hash 地址,显示不同的组件
2.1 前端路由的工作方式
① 用户
点击
了页面上的路由链接
② 导致了
URL 地址栏
中的Hash 值
发生了变化③
前端路由监听了到 Hash 地址的变化
④ 前端路由把当前
Hash 地址对应的组件
渲染到浏览器中
强调:前端路由,指的就是 Hash 地址 和 组件 之间的关系
Vue - router 的基本使用
1. 什么是 Vue - router
vue-router
是 vue.js 官方给出的路由解决方案
。vue-router 的官方文档地址:https://router.vuejs.org/zh/
2. vue - router 的使用步骤
① 安装 vue-router 包
1. npm i vue-router@3.5.2 -S 2. npm i 3. npm run serve
② 创建路由模块
在 src 源代码目录下,新建 router/index.js 路由模块 ,并初始化代码 <script> // 1. 引入 Vue 和 VueRouter 的包 import Vue from 'vue' import VueRouter from 'vue-router' // 2. 调用 Vue.use() 函数,把 VueRouter 安装为插件 Vue.use(VueRouter) // 3. 创建路由的实例对象 const router = new VueRouter(); // 4. 导出路由实例对象 export default router </script>
③ 挂载路由模块
在 src/main.js 入口文件中,导入并挂载路由模块 <script> //1. 导入路由模块 import router from '@/router/index.js' new Vue({ render: h => h(App), // 2. 挂载路由模块 router }).$mount('#app') </script>
④ 配置路由规则
在 src/router/index.js 路由模块中,通过 routes数组 声明路由的匹配规则 <script> // 引入要显示的组件 import Home from '@/componments/Home.vue' import Movie from '@/componments/Movie.vue' import About from '@/componments/About.vue' const router = new VueRouter({ // 使用 routes 选项配置路由规则 // 路由规则:hash 地址和对应的组件 routes:[ // {path:'hash地址',component:Home} // 注意:path 里面的 hash 地址是不需要加 # 的 {path:'/home',component:Home}, {path:'/movie',component:Movie}, {path:'/about',component:About} ] }) </script>
⑤ 声明路由链接和占位符
在 src/App.vue 组件中,使用 vue-router 提供的 <router-link> 和 <router-view> 声明 路由链接 和 路由占位符 <template> <div class="app-container"> <h1>App 根组件</h1> <!-- 声明路由跳转链接 --> <router-link to="/home">首页</router-link> <router-link to="/movie">电影</router-link> <router-link to="/about">关于</router-link> <hr /> <!-- 声明路由占位符 --> <router-view></router-view> </div> </template> <script> </script>
3. vue-router 的常见用法 - 路由重定向
路由重定向
路由重定向指的是:用户在访问
地址A
的时候,强制
用户跳转到地址C
,从而展示 组件C 对应的组件页面
通过路由规则的
redirect
属性,指定一个新的路由地址,可以很方便设置路由重定向:<script> const router = new VueRouter({ // routes:是用来配置路由规则的 routes: [ // {path:'当前访问地址',redirect:'重定向的地址'} // redirect 重定向,当访问 / 这个地址的时候,强制跳转到 redirect "/home" 这个地址 { path: '/', redirect: '/home' }, { path: '/home', component: Home }, { path: '/movie', component: Movie }, { path: '/about', component: About } ] }); </script>
4. vue-router 的常见用法 - 嵌套路由的概念
嵌套路由
在本身就是通过路由展示的组件中,再使用路由去控制其他组件的展示,就会形成嵌套路由。
这种通过路由实现
组件的嵌套展示
,叫做嵌套路由第一步:声明 子路由规则
在 src/router/index.js 路由模块中,使用 children 属性声明子路由规则: <script> import Tab1 from '@/components/tabs/Tab1.vue' import Tab2 from '@/components/tabs/Tab2.vue' const router = new VueRouter({ routes:[ { path:'/about', component:About, // 要在哪个组件中展示其他组件,children 就是加在哪个路由规则下面 // 通过 children 属性,定义子路由规则 // 在哪里加了子组件,就在哪个组件中加子路由链接和占位符 children:[ {path:'/about/tab1',component:Tab1}, {path:'/about/tab2',component:Tab2} ] } ] }) </script>
第二步:声明 子路由链接 和 子路由占位符
在 About.vue 组件中,声明 tab1 和 tab2 的子路由链接以及子路由占位符。 <!-- 在哪里加了子组件,就在哪个组件中加子路由链接和占位符 --> <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>
5. vue-router 的常见用法 - 动态路由
动态路由的概念
动态路由指的是:把 Hash 地址中
动态变化的部分
定义为一个动态的参数项
,从而提高路由规则的复用性
在 vue-router 中使用
英文的冒号(:)
来定义路由的参数项<script> // 在路由地址中声明动态参数项 // 将动态可变的部分使用(:动态参数项的名称) 代替 // 匹配组件传递过来的 所有/movie/后面的id值 // 给哪个组件传递,就去哪个组件去使用参数 {path:'/movie/:id',component:Movie} // 将以下 3个路由规则,合并成一个,提高路由规则复用性 {path:'/movie/1',component:Movie}, {path:'/movie/2',component:Movie}, {path:'/movie/3',component:Movie} </script>
6. vue-router 的常见用法 - 通过 $route.params 获取动态路由参数
通过 $route.params 获取动态路由参数
在
动态路由
渲染出来的组件中,可以使用 this.$route.params
对象访问到动态匹配的参数值
this.$route 里面存放的是当前页面路由的相关信息
<template> <div class="movie-container"> <!-- this.$route 里面存放的是当前路由的相关信息 --> <!-- id是我们在 index.js 中传递过来的那个参数 --> <!-- 语法:this.$route.params.参数 --> <h3>Movie 组件 --- {{$route.params.id}}</h3> <button @click="getRoute">打印 this.$route </button> </div> </template> <script> export default { name:'Movie', methods:{ getRoute(){ // $route 对象里面有一个params对象,里面就是我们传递的参数,参数名:参数值,是一个键值对 console.log(this.$route) } } } </script>
7. vue-router 的常见用法 - 使用 props 接收路由参数
使用 props 接收路由参数
为了
简化路由参数的获取形式
, vue-router 允许在路由规则
中开启 props 传参
,那么在组件中就可以使用 props 来接收路由上的参数了步骤一: 在路由规则中开启 props 选项
<!-- 在路由规则中,想给谁传递,就在它的规则里面写入允许props传参 --> <!-- 第二种获取的方法,在传的路由规则中加一个props为true,表示允许传值 --> {path:'/movie/:id',component:Movie,props:true}
步骤二:在组件中使用 props 接收路由参数
<template> <div class="movie-container"> <!-- 在这里可以直接使用props传递过来的值 --> <h3>Movie 组件 --- {{id}}</h3> </div> </template> <script> export default { // 使用 props 接收路由参数 // 在这里定义一个props,定义传过来的值 props:['id'] } </script>
8. vue-router 的常见用法 - 编程式导航
声明式导航 & 编程式导航
- 在浏览器中,
点击链接
实现路由跳转的方式,叫做声明式导航
- 普通页面的 标签
- vue-router的 标签
- 在浏览器中,
调用 JS API 方法
实现路由跳转的方式,叫做编程式导航
- 普通网页中调用
location.href
跳转 - vue-router 的跳转 调用
this.$router.push('hash地址')
- $router 指的是定义的 router 实例对象
- 跳转到指定 hash 地址,并 增加 一条历史记录
- vue-router 的历史记录前进后退 调用
this.$router.go(数值n)
- 实现导航历史 前进、后退
- 普通网页中调用
1. $router.push
调用
this.$router.push()
方法,可以跳转到指定的 hash 地址
,从而展示对应的组件页面<template> <button @click="goAbout">使用编程式导航,跳转到关于页面</button> </template> <script> export default { methods:{ goAbout(){ this.$router.push('/about') } } } </script>
2. $router.go
调用
this.$router.go()
方法,可以在浏览历史中前进和后退
,类似于浏览器的前进后退功能<template> <button @click="goBack">后退</button> </template> <script> export default { methods:{ goback(){ this.$router.go(-1) } } } </script>
Vue - router 的常见用法 - 全局的前置守卫 beforeEach
全局的前置守卫
每次发生路由的
导航跳转
时,还没有真正发生跳转之前,会触发全局前置守卫
因此,我们可以在全局前置守卫中,对每个路由进行
访问权限
的控制:// 在 router/index.js 中: // 创建路由对象 const router = new VueRouter({ ... }) // 声明全局前置守卫 // 每次发生路由跳转的时候,都会触发 beforeEach 中的 fn 回调函数 // 语法:router.beforeEach(fn) router.beforeEach(()=>{ console.log('触发了 beforeEach 中的 fn 回调函数'); // 在这里可以做一些权限控制的操作 })
vue-router 的常见用法 - 守卫方法的 3 个形参
守卫方法的 3 个形参
全局前置守卫的回调函数中接收 3 个形参,格式为:
// 声明全局前置守卫 // 每次路由跳转,都会触发这个全局前置守卫 beforeEach 的回调函数 // 语法:router.beforeEach(回调函数) router.beforeEach((to, from, next) => { // 要去哪儿 从哪儿来 放行 // to:要访问的页面的路由信息对象 console.log(to); // from:将要离开的页面的路由信息对象 console.log(from); // next:它是一个函数,如果调用 next ,表示放行的意思,让你完成本次路由的跳转 // 如果不调用 next,表示本次跳转失败 next(); // 可以在这里做权限控制的工作 })
next 函数的 3 种调用方式
vue-router 的常见用法 - 控制后台主页的访问权限
控制后台主页的访问权限
<script>
router.beforeEach(to,from,next)=>{
// 可以在这里做权限控制的工作
// 1.判断用户访问的页面是不是后台主页,也就是hash为 '/main'
if(to.path === '/main'){
// 访问的页面是后台主页
// 2.判断用户是否登录,进行权限控制
const token = localStorage.getItem('token');
--------------------------------------------------------------------------------
if判断:
if(token){
// 登录了,直接放行
next();
}else{
// 没登录,跳转到登录页
// next('hash地址'): 表示跳转到 hash 指定的那个页面
next('/login')
}
--------------------------------------------------------------------------------
三元表达式 token ? next() : next('/login')
--------------------------------------------------------------------------------
}else{
// 访问的页面不是后台主页,直接放行
next();
}
}
</script>
vue-router 的常见用法 - 模拟登录操作
实现登录操作
<template>
<div class="login-container">
<h3>Login 组件</h3>
<hr />
<div>
<!-- 账号 -->
<label>账号:<input type="text" class="form-control" v-model="username" @keyup.enter="enter"/></label>
</div>
<div>
<!-- 密码 -->
<label>密码:<input type="password" class="form-control" v-model="password" @keyup.enter="enter"/></label>
</div>
<br />
<!-- 登录按钮 -->
<button @click="login" class="btn btn-primary">登录</button>
</div>
</template>
<script>
export default {
name: 'Login',
data() {
return {
username: '',
password: ''
}
},
methods:{
login(){
// 1. 用户名密码是否正确
if(this.username === 'admin' && this.password==='123456'){
// 登陆成功
// 1.1 将 token 存到本地
localStorage.setItem('token','Euhporia');
// 1.2 跳转到后台主页 /main
this.$router.push('/main')
}else{
// 登录失败
// 2.1 清除token
alert('用户名或密码错误,请重新输入...');
this.username = '';
this.password = '';
localStorage.removeItem('token');
}
},
enter(){
this.login();
}
}
}
</script>
<style lang="less" scoped>
.login-container {
min-height: 200px;
background-color: #b0cdf3;
padding: 15px;
> a {
margin-right: 10px;
}
}
</style>