URL(Uniform Resource Locator,统一资源定位符)用于定位网络上的资源
格式:协议://主机号 : 端口号/路径 ? 参数
示例:https://www.euphoria:8083/images/cat.png?name=ls#abc
- “#” 号后面的部分,专业术语为 “Hash地址”
- Hash 地址发生变化,
不会导致浏览器页面的刷新- Hash 地址发生变化,
会形成浏览器历史记录- vue 就是基于 hash 的这些特性来做路由的跳转,实现页面切换
多页应用与后台路由:多页应用中,想要切换页面就是跳转到一个新的 html 页面,路由工作是由后端完成的
单页应用与前端路由:只有唯一的一个 HTML 页面,想要
切换页面只能切换组件,这种切换组件达到页面切换的效果,就是前端路由前端路由:访问不同的 hash 地址,显示不同的组件
① 用户
点击了页面上的路由链接② 导致了
URL 地址栏中的Hash 值发生了变化③
前端路由监听了到 Hash 地址的变化④ 前端路由把当前
Hash 地址对应的组件渲染到浏览器中
强调:前端路由,指的就是 Hash 地址 和 组件 之间的关系
vue-router是 vue.js 官方给出的路由解决方案。vue-router 的官方文档地址:https://router.vuejs.org/zh/
① 安装 vue-router 包
1. npm i vue-router@3.5.2 -S 2. npm i 3. npm run serve
- 1
② 创建路由模块
在 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>
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
③ 挂载路由模块
在 src/main.js 入口文件中,导入并挂载路由模块 <script> //1. 导入路由模块 import router from '@/router/index.js' new Vue({ render: h => h(App), // 2. 挂载路由模块 router }).$mount('#app') script>
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
④ 配置路由规则
在 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>
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
⑤ 声明路由链接和占位符
在 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>
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
路由重定向指的是:用户在访问
地址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>
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
在本身就是通过路由展示的组件中,再使用路由去控制其他组件的展示,就会形成嵌套路由。
这种通过路由实现
组件的嵌套展示,叫做嵌套路由第一步:声明 子路由规则
在 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>
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
第二步:声明 子路由链接 和 子路由占位符
在 About.vue 组件中,声明 tab1 和 tab2 的子路由链接以及子路由占位符。 <template> <div class="about-container"> <h3>About 组件h3> <router-link to="/about/tab1">Tab1router-link> <router-link to="/about/tab2">Tab2router-link> <hr /> <router-view>router-view> div> template>
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
动态路由指的是:把 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>
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
在
动态路由渲染出来的组件中,可以使用 this.$route.params对象访问到动态匹配的参数值this.$route 里面存放的是当前页面路由的相关信息
<template> <div class="movie-container"> <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>
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
为了
简化路由参数的获取形式, vue-router 允许在路由规则中开启 props 传参,那么在组件中就可以使用 props 来接收路由上的参数了步骤一: 在路由规则中开启 props 选项
{path:'/movie/:id',component:Movie,props:true}
- 1
- 2
- 3
步骤二:在组件中使用 props 接收路由参数
<template> <div class="movie-container"> <h3>Movie 组件 --- {{id}}h3> div> template> <script> export default { // 使用 props 接收路由参数 // 在这里定义一个props,定义传过来的值 props:['id'] } script>
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
点击链接 实现路由跳转的方式,叫做 声明式导航
调用 JS API 方法 实现路由跳转的方式,叫做 编程式导航
location.href 跳转this.$router.push('hash地址')
this.$router.go(数值n)
调用
this.$router.push()方法,可以跳转到指定的 hash 地址,从而展示对应的组件页面<template> <button @click="goAbout">使用编程式导航,跳转到关于页面button> template> <script> export default { methods:{ goAbout(){ this.$router.push('/about') } } } script>
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
调用
this.$router.go()方法,可以在浏览历史中前进和后退,类似于浏览器的前进后退功能<template> <button @click="goBack">后退button> template> <script> export default { methods:{ goback(){ this.$router.go(-1) } } } script>
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
每次发生路由的
导航跳转时,还没有真正发生跳转之前,会触发全局前置守卫因此,我们可以在全局前置守卫中,对每个路由进行
访问权限的控制:// 在 router/index.js 中: // 创建路由对象 const router = new VueRouter({ ... }) // 声明全局前置守卫 // 每次发生路由跳转的时候,都会触发 beforeEach 中的 fn 回调函数 // 语法:router.beforeEach(fn) router.beforeEach(()=>{ console.log('触发了 beforeEach 中的 fn 回调函数'); // 在这里可以做一些权限控制的操作 })
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
全局前置守卫的回调函数中接收 3 个形参,格式为:
// 声明全局前置守卫 // 每次路由跳转,都会触发这个全局前置守卫 beforeEach 的回调函数 // 语法:router.beforeEach(回调函数) router.beforeEach((to, from, next) => { // 要去哪儿 从哪儿来 放行 // to:要访问的页面的路由信息对象 console.log(to); // from:将要离开的页面的路由信息对象 console.log(from); // next:它是一个函数,如果调用 next ,表示放行的意思,让你完成本次路由的跳转 // 如果不调用 next,表示本次跳转失败 next(); // 可以在这里做权限控制的工作 })
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14


<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>
<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>