vue路由笔记整理
what is 路由 and SPA
路由?
①一个路由就是一组映射关系(key-value)
②key为路径,value可能是function或者component
不管生活中使用的路由器还是开发中遇到的router,路由都是一种对应关系,即key与value的对应关系。
SPA?
SPA指的是一个web网站只有一个唯一的Html页面,所有的组件的展示与切换都在这一个页面来完成。此时,不同组件之间的切换需要通过前端路由来实现。
①单页Web应用(SPA)
②整个应用只有一个完整的页面。vue项目中所有的组件的信息都会展示到public/index.html中
③点击页面中的导航链接不会刷新页面,只会做页面的局部更新。
④数据需要通过ajax请求获取
结论:在SPA项目中,不同功能的实现,需要路由来完成。
后端路由?
①理解:value是function,用于处理客户端提交的请求。
②工作过程:服务器接收到一个请求时,根据请求路径找到匹配的函数来处理请求,返回响应数据。
前端路由?
理解:value是component,用于展示页面内容。
工作过程:当浏览器的路径改变时,对应的组件就会显示。
①hash地址与组件之间的对应关系。
②Hash地址就是锚链接 ,在一个页面中进行组件之间的跳转;而超链接,会跳转到新的页面 锚链接与超链接的区别
③在浏览器console中获取完整的地址,location.href 在一个页面中跳转到不同的路由,#后面的叫做hash地址 location.hash
路由的hash模式和history模式
hash模式和history模式区别
hash模式和history模式 面试区别
前端路由的工作方式
用户点击路由链接,浏览器url上的hash地址发生了变化,前端路由监听hash地址的变化,然后前端路由将hash地址对应的组件渲染到浏览器中
手动模拟前端路由实现
这里我们手动取监听hash地址的变化,后面我们会引入Vue-Router这个第三方库,来帮我们实现路由的的监听和切换
<template>
<div class="app-container">
<h1>App 根组件</h1>
<a href="#/home">首页</a>
<a href="#/movie">电影</a>
<a href="#/about">关于</a>
<hr />
<component :is="comName"></component>
</div>
</template>
<script>
// 导入组件
import Home from '@/components/Home.vue'
import Movie from '@/components/Movie.vue'
import About from '@/components/About.vue'
export default {
name: 'App',
data() {
return {
// 在动态组件的位置,要展示的组件的名字,值必须是字符串
comName: 'Home'
}
},
created() {
// 只要当前的 App 组件一被创建,就立即监听 window 对象的 onhashchange 事件
window.onhashchange = () => {
console.log('监听到了 hash 地址的变化', location.hash)
switch (location.hash) {
case '#/home':
this.comName = 'Home'
break
case '#/movie':
this.comName = 'Movie'
break
case '#/about':
this.comName = 'About'
break
}
}
},
// 注册组件
components: {
Home,
Movie,
About
}
}
</script>
<style lang="less" scoped>
.app-container {
background-color: #efefef;
overflow: hidden;
margin: 10px;
padding: 15px;
> a {
margin-right: 10px;
}
}
</style>
vue中使用路由的注意点
①路由组件通常粗放在pages文件夹,一般组件存放在components文件夹,路由组件也就是配置了路由的
②通过切换,“隐藏”了的路由组件,默认是被销毁掉的,需要的时候再去挂载。
③每个组件都有自己的
r
o
u
t
e
属性,里面存储着自己的路由信息。④整个应用只有一个
r
o
u
t
e
r
,可以通过组件的
route属性,里面存储着自己的路由信息。 ④整个应用只有一个router,可以通过组件的
route属性,里面存储着自己的路由信息。④整个应用只有一个router,可以通过组件的router属性获取到。
⑤
r
o
u
t
e
是参数对象,可以用来传参;
route是参数对象,可以用来传参;
route是参数对象,可以用来传参;router是导航对象,组件之间的切换。
引入vue-router的步骤
vue-router官网地址
vue-router是vue.js官方给出的路由解决方案你。他只能结合vue项目来使用,能够轻松管理SPA项目中组件的切换。
①安装
②创建路由模块
③导入并挂载路由模块
④声明路由链接和占位符
⑤通过routes数组声明路由的匹配规则
vue-router的常见用法
①路由重定向
②嵌套路由
声明子路由链接和子路由占位符
标签中可以添加active-class=“active”属性来实现高亮效果
active-class 选择样式时根据路由中的路径(to=“/home”)去匹配,然后显示
通过children属性来声明子路由规则
嵌套路由注意点
路由匹配的过程中,路由会自动遍历子路由,会给他加上 / ,所以这里不要重复加了
③动态路由匹配
什么是动态路由?
$route.params对象
使用props接收路由参数
④声明式导航&编程式导航
vue-router中的编程式导航API
$router.push()
$router.replace()
$router.go()
$router.back() && $router.forward()
⑤导航守卫
全局前置守卫
守卫方法的三个形参
next()函数的三种调用方式
控制后台主页的访问权限
给路由添加鉴权属性
全局后置路由守卫
后置路由守卫实现的效果,在路由跳转之后修改相应的title
// 该文件专门用于创建整个应用的路由器
import VueRouter from 'vue-router'
//引入组件
import About from '../pages/About'
import Home from '../pages/Home'
import News from '../pages/News'
import Message from '../pages/Message'
import Detail from '../pages/Detail'
//创建并暴露一个路由器
const router = new VueRouter({
routes:[
{
name:'guanyu',
path:'/about',
component:About,
meta:{title:'关于'}
},
{
name:'zhuye',
path:'/home',
component:Home,
meta:{title:'主页'},
children:[
{
name:'xinwen',
path:'news',
component:News,
meta:{isAuth:true,title:'新闻'}
},
{
name:'xiaoxi',
path:'message',
component:Message,
meta:{isAuth:true,title:'消息'},
children:[
{
name:'xiangqing',
path:'detail',
component:Detail,
meta:{isAuth:true,title:'详情'},
//props的第一种写法,值为对象,该对象中的所有key-value都会以props的形式传给Detail组件。
// props:{a:1,b:'hello'}
//props的第二种写法,值为布尔值,若布尔值为真,就会把该路由组件收到的所有params参数,以props的形式传给Detail组件。
// props:true
//props的第三种写法,值为函数
props($route){
return {
id:$route.query.id,
title:$route.query.title,
a:1,
b:'hello'
}
}
}
]
}
]
}
]
})
//全局前置路由守卫————初始化的时候被调用、每次路由切换之前被调用
router.beforeEach((to,from,next)=>{
console.log('前置路由守卫',to,from)
if(to.meta.isAuth){ //判断是否需要鉴权
if(localStorage.getItem('school')==='atguigu'){
next()
}else{
alert('学校名不对,无权限查看!')
}
}else{
next()
}
})
//全局后置路由守卫————初始化的时候被调用、每次路由切换之后被调用
router.afterEach((to,from)=>{
console.log('后置路由守卫',to,from)
document.title = to.meta.title || '硅谷系统'
})
export default router
独享路由守卫
组件内路由守卫
⑥路由的query参数
注意1:在 hash 地址中, / 后面的参数项,叫做“路径参数” 比如/1 /2 这些动态参数 是路径参数
在路由“参数对象”中,需要使用 this.$route.params 来访问路径参数
注意2:在 hash 地址中,? 后面的参数项,叫做“查询参数”
在路由“参数对象”中,需要使用 this.$route.query 来访问查询参数
注意3:在 this.$route 中,path 只是路径部分;fullPath 是完整的地址
⑦路由的params参数
⑧路由命名 用于简化跳转
⑨路由的props配置
组件来接收props传递的数据
<template>
<div>
<h1>{{msg}}</h1>
<h2>学生姓名:{{name}}</h2>
<h2>学生性别:{{sex}}</h2>
<h2>学生年龄:{{myAge+1}}</h2>
<button @click="updateAge">尝试修改收到的年龄</button>
</div>
</template>
<script>
export default {
name:'Student',
data() {
console.log(this)
return {
msg:'我是一个尚硅谷的学生',
myAge:this.age
}
},
methods: {
updateAge(){
this.myAge++
}
},
//简单声明接收
// props:['name','age','sex']
//接收的同时对数据进行类型限制
/* props:{
name:String,
age:Number,
sex:String
} */
//接收的同时对数据:进行类型限制+默认值的指定+必要性的限制
props:{
name:{
type:String, //name的类型是字符串
required:true, //name是必要的
},
age:{
type:Number,
default:99 //默认值
},
sex:{
type:String,
required:true
}
}
}
</script>
⑩router-link的replace属性
11、 缓存路由组件
include中包含的是要缓存的组件的名称,如果keep-alive中不加include,那么所有在router-view中展示的组件都会被缓存
<!-- 缓存多个路由组件 -->
<!-- <keep-alive :include="['News','Message']"> -->
<!-- 缓存一个路由组件 -->
<keep-alive include="News">
<router-view></router-view>
</keep-alive>
<template>
<ul>
<li>news001 <input type="text"></li>
<li>news002 <input type="text"></li>
<li>news003 <input type="text"></li>
</ul>
</template>
<script>
export default {
name:'News',//这是组件名称
beforeDestroy() {
console.log('News组件即将被销毁了')
},
}
</script>
12、路由所独有的两个钩子
vue-router的具体使用
①整体架子
本地项目 vue2/day7/router-demo1
②router/index.js
// src/router/index.js 就是当前项目的路由模块
import Vue from 'vue'
import VueRouter from 'vue-router'
// 导入需要的组件
import Home from '@/components/Home.vue'
import Movie from '@/components/Movie.vue'
import About from '@/components/About.vue'
import Tab1 from '@/components/tabs/Tab1.vue'
import Tab2 from '@/components/tabs/Tab2.vue'
import Login from '@/components/Login.vue'
import Main from '@/components/Main.vue'
// 把 VueRouter 安装为 Vue 项目的插件
// Vue.use() 函数的作用,就是来安装插件的
Vue.use(VueRouter)
// 创建路由的实例对象
const router = new VueRouter({
// routes 是一个数组,作用:定义 “hash 地址” 与 “组件” 之间的对应关系
routes: [
// 重定向的路由规则
{ path: '/', redirect: '/home' },
// 路由规则
{ path: '/home', component: Home },
// 需求:在 Movie 组件中,希望根据 id 的值,展示对应电影的详情信息
// 可以为路由规则开启 props 传参,从而方便的拿到动态参数的值
{ path: '/movie/:mid', component: Movie, props: true },
{
path: '/about',
component: About,
// redirect: '/about/tab1',
children: [
// 子路由规则
// 默认子路由:如果 children 数组中,某个路由规则的 path 值为空字符串,则这条路由规则,叫做“默认子路由”
{ path: '', component: Tab1 },
{ path: 'tab2', component: Tab2 }
]
},
{ path: '/login', component: Login },
{ path: '/main', component: Main }
]
})
// 为 router 实例对象,声明全局前置导航守卫
// 只要发生了路由的跳转,必然会触发 beforeEach 指定的 function 回调函数
router.beforeEach(function(to, from, next) {
// to 表示将要访问的路由的信息对象
// from 表示将要离开的路由的信息对象
// next() 函数表示放行的意思
// 分析:
// 1. 要拿到用户将要访问的 hash 地址
// 2. 判断 hash 地址是否等于 /main。
// 2.1 如果等于 /main,证明需要登录之后,才能访问成功
// 2.2 如果不等于 /main,则不需要登录,直接放行 next()
// 3. 如果访问的地址是 /main。则需要读取 localStorage 中的 token 值
// 3.1 如果有 token,则放行
// 3.2 如果没有 token,则强制跳转到 /login 登录页
if (to.path === '/main') {
// 要访问后台主页,需要判断是否有 token
const token = localStorage.getItem('token')
if (token) {
next()
} else {
// 没有登录,强制跳转到登录页
next('/login')
}
} else {
next()
}
})
export default router
③main.js
import Vue from 'vue'
import App from './App2.vue'
// 导入路由模块,目的:拿到路由的实例对象
// 在进行模块化导入的时候,如果给定的是文件夹,则默认导入这个文件夹下,名字叫做 index.js 的文件
import router from '@/router'
// 导入 bootstrap 样式
import 'bootstrap/dist/css/bootstrap.min.css'
// 全局样式
import '@/assets/global.css'
Vue.config.productionTip = false
new Vue({
render: h => h(App),
// 在 Vue 项目中,要想把路由用起来,必须把路由实例对象,通过下面的方式进行挂载
// router: 路由的实例对象
router
}).$mount('#app')
④App2.vue
<template>
<div class="app-container">
<h1>App2 组件</h1>
<!-- 当安装和配置了 vue-router 后,就可以使用 router-link 来替代普通的 a 链接了 -->
<!-- <a href="#/home">首页</a> -->
<router-link to="/home">首页</router-link>
<!-- 注意1:在 hash 地址中, / 后面的参数项,叫做“路径参数” 比如/1 /2 这些动态参数 是路径参数 -->
<!-- 在路由“参数对象”中,需要使用 this.$route.params 来访问路径参数 -->
<!-- 注意2:在 hash 地址中,? 后面的参数项,叫做“查询参数” -->
<!-- 在路由“参数对象”中,需要使用 this.$route.query 来访问查询参数 -->
<!-- 注意3:在 this.$route 中,path 只是路径部分;fullPath 是完整的地址 -->
<!-- 例如: -->
<!-- /movie/2?name=zs&age=20 是 fullPath 的值 -->
<!-- /movie/2 是 path 的值 -->
<router-link to="/movie/1">洛基</router-link>
<router-link to="/movie/2?name=zs&age=20">雷神</router-link>
<router-link to="/movie/3">复联</router-link>
<router-link to="/about">关于</router-link>
<hr />
<!-- 只要在项目中安装和配置了 vue-router,就可以使用 router-view 这个组件了 -->
<!-- 它的作用很单纯:占位符 -->
<router-view></router-view>
</div>
</template>
<script>
export default {
name: 'App'
}
</script>
<style lang="less" scoped>
.app-container {
background-color: #efefef;
overflow: hidden;
margin: 10px;
padding: 15px;
> a {
margin-right: 10px;
}
}
</style>
⑤About.vue
<template>
<div class="about-container">
<h3>About 组件</h3>
<!-- 子级路由链接 -->
<router-link to="/about">tab1</router-link>
<router-link to="/about/tab2">tab2</router-link>
<hr />
<!-- 子级路由占位符 -->
<router-view></router-view>
</div>
</template>
<script>
export default {
name: 'About'
}
</script>
<style lang="less" scoped>
.about-container {
min-height: 200px;
background-color: skyblue;
padding: 15px;
> a {
margin-right: 10px;
}
}
</style>
⑥Home.vue
<template>
<div class="home-container">
<h3>Home 组件</h3>
<hr />
<button @click="gotoLk">通过 push 跳转到“洛基”页面</button>
<button @click="gotoLk2">通过 replace 跳转到“洛基”页面</button>
<router-link to="/main">访问后台主页</router-link>
</div>
</template>
<script>
export default {
name: 'Home',
methods: {
gotoLk() {
// 通过编程式导航 API,导航跳转到指定的页面
this.$router.push('/movie/1')
},
gotoLk2() {
this.$router.replace('/movie/1')
}
}
}
</script>
<style lang="less" scoped>
.home-container {
min-height: 200px;
background-color: pink;
padding: 15px;
}
</style>
⑦Login.vue
<template>
<div>
<h3>Login 登录页面</h3>
</div>
</template>
<script>
export default {}
</script>
<style></style>
⑧Main.vue
<template>
<div>
<h3>Main 后台主页,未登录不允许访问!!!</h3>
</div>
</template>
<script>
export default {}
</script>
<style></style>
⑨Movie.vue
<template>
<div class="movie-container">
<!-- this.$route 是路由的“参数对象” -->
<!-- this.$router 是路由的“导航对象” -->
<h3>Movie 组件 --- {{ $route.params.mid }} --- {{ mid }}</h3>
<button @click="showThis">打印 this</button>
<button @click="goback">后退</button>
<!-- 在行内使用编程式导航跳转的时候,this 必须要省略,否则会报错! -->
<button @click="$router.back()">back 后退</button>
<button @click="$router.forward()">forward 前进</button>
</div>
</template>
<script>
export default {
name: 'Movie',
// 接收 props 数据
props: ['mid'],
methods: {
showThis() {
console.log(this)
},
goback() {
// go(-1) 表示后退一层
// 如果后退的层数超过上限,则原地不动
this.$router.go(-1)
}
}
}
</script>
<style lang="less" scoped>
.movie-container {
min-height: 200px;
background-color: lightsalmon;
padding: 15px;
}
</style>
⑩关键知识点
this.$route 是路由的“参数对象”
this.$route.params用来获取路径参数 / 后面的是路径参数
this.$route.query用来获取查询参数 ?后面的是查询参数
fullPath包括路径参数和查询参数
path只包含路径,无查询参数
this.$router 是路由的“导航对象”
this.$router.push() 跳转到某一个组件,有历史记录
this.$router.replace() 跳转,替换掉当前的历史记录
this.$router.go() 跳转多少页
this.$router.back() 后退
this.$router.forward() 前进
路由守卫
只记录了常用的 前置路由守卫,其他参考官网