前言:什么是路由
1.对于普通的网站,所有的超链接都是URL地址,所有的URL地址都对应服务器上对应的资源;
A : http://127.0.0.1:5500/12.路由的使用.html/registerB : http://127.0.0.1:5500/12.路由的使用.html/loginapp.get("/login",(req,res)=>{})app.get("/register",(req,res)=>{})当我们的网址由A到B的时候,此时会向服务器发送请求(也就是此时服务器要处理login请求)
2.对于单页面应用程序来说,主要通过URL中的hash(#号)来实现不同页面之间的切换,同时hash有一个特点,HTTP请求中不会包含hash相关的内容;
A : http://127.0.0.1:5500/12.路由的使用.html#/registerB : http://127.0.0.1:5500/12.路由的使用.html#/login当我们的网址由A到B的时候,此时网址中变化是#后面的内容,此时不会向服务器发送请求。这种方式我们称为前端路由。当我们由#/register切换到#/login变化的是:当前的路由地址所对应的组件信息
3.在单页面应用程序中,这种通过hash改变来切换页面的方式,称作前端路由(区别于后端路由);
一、路由配置
1-1 安装依赖
yarn add vue-router
1-2 在App.vue
<template><div id="app"><router-view></router-view></div></template>
1-3 在routers文件夹下
//index.jsimport Vue from 'vue';import Router from 'vue-router'import Music from '@/pages/Music.vue'import Mv from '@/pages/Mv.vue'Vue.use(Router);export default new Router({mode:"hash", //historyroutes:[{path:'/music',name:"music",component:Music},{path:'/mv',name:"mv",component:Mv}]})
1-3-1 异步路由
进入页面时才会触发路由
export default new Router({mode:"hash",routes:[...{path:"/detail",name:"detail",/* 异步路由 */component:()=>import('@/pages/Detail')}]})
1-4 在main.js下
import router from './routers'Vue.config.productionTip = falsenew Vue({router,render: h => h(App),}).$mount('#app')
二、router-link 切换组件
//App.vue下<template><div id="app"><div id="nav"><router-link to="/music">音乐</router-link><router-link to="/mv">MV</router-link></div><router-view></router-view></div></template>
常用属性:
| 属性 | 类型 | 说明 | 示例 |
|---|---|---|---|
| to | string \ Location | 表示目标路由的链接。当被点击后,内部会立刻把to的值传到router.push(),所以这个值可以是一个字符串或者是描述目标位置的对象。 |
<router-link to="home">Home</router-link> |
| replace | boolean(默认flase) | 设置replace属性的话,当点击时,会调用 router.replace()而不是 router.push(),于是导航后不会留下 history 记录。 |
<router-link :to="{ path: '/abc'}" replace></router-link> |
| append | boolean(默认flase) | 设置append属性后,则在当前 (相对) 路径前添加基路径。例如,我们从 /a导航到一个相对路径 b,如果没有配置 append,则路径为/b,如果配了,则为/a/b |
<router-link :to="{ path: 'relative/path'}" append></router-link> |
| tag | string(默认 ‘a’) | 有时候想要 渲染成某种标签,例如 <li>于是我们使用tagprop 类指定何种标签,同样它还是会监听点击,触发导航。 |
<router-link to="/foo" tag="li">foo</router-link> |
| active-class | string(默认 “router-link-active”) | 设置 链接激活时使用的CSS 类名。默认值可以通过路由的构造选项linkActiveClass来全局配置。 |
|
| exact | boolean(默认 false) | “是否激活” 默认类名的依据是 inclusive match (全包含匹配)。 举个例子,如果当前的路径是 /a 开头的,那么 也会被设置 CSS 类名。 |
这个链接只会在地址为 / 的时候被激活: <router-link to="/" exact> |
| event | string \ Array (默认 ‘click’) | 声明可以用来触发导航的事件。可以是一个字符串或是一个包含字符串的数组。 |
|
| exact-active-class | string 默认 ‘router-link-exact-active’ | 配置当链接被精确匹配的时候应该激活的 class。注意默认值也是可以通过路由构造函数选项linkExactActiveClass进行全局配置的。 |
三、路由传值
3-1 动态路由
传参:<router-link :to="'/detail/'+item.id" tag="button">跳转到detail</router-link>接收传参:this.$route.params.id;
router配置
主页
详情页
3-2 get传值
3-2-1 在列表页传值this.$router.push()
<div @click="handleClick(data.id)"></div>
<router-link :to=`/detail?id=${id}` tag="button">跳转到detail</router-link>
export default {name:"Item",props:{data:{type:Object,required:true}},methods:{handleClick(id){console.log(id)this.$router.push(`/detail?id=${id}`)}}};
3-2-2 在详情页接收值this.$route.query
export default {name:"Detail",computed:{id(){return this.$route.query.id}}};
mouted(){var id = this.$route.query.id}
3-2-3 在详情页跳转回列表页
methods: {toggle() {this.$router.back();}}
3-3 关于路由跳转
3-3-1 router-link方式
不带参数:
<router-link :to="{name:'home'}">
带参数:params传参数
html 取参 $route.params.idscript 取参 this.$route.params.id<router-link :to="{name:'home', params: {id:1}}">
带参数:query传参数 (类似get,url后面会显示参数)
注意点:如果使用path,name不可以和params共用html 取参 $route.query.idscript 取参 this.$route.query.id<router-link :to="{name:'home', query: {id:1}}">
3-3-2 this.$router.push() 编程式导航
不带参数:
this.$router.push('/home')this.$router.push({name:'home'})this.$router.push({path:'/home'})
query传参:
this.$router.push({name:'home',query: {id:'1'}})this.$router.push({path:'/home',query: {id:'1'}})
params传参:
params只能用name来引入路由,不能与path一起用
this.$router.push({name:'home',params: {id:'1'}})
注:
- query类似get,跳转之后页面url后面会拼接参数,类似?id=1,非重要性的可以这样传,密码之类还是用params刷新页面id还在;
- params类似post,跳转之后页面url后面不会拼接参数,但是刷新页面id会消失。
3-4 route和router的区别
$route是“路由信息对象”,包括path,params,hash,query,fullPath,matched,name等路由信息参数。$router是“路由实例”对象,包括了路由的跳转方法,钩子函数等。
3-5 meta的使用
meta字段(元数据),直接在路由配置的时候,给每个路由添加一个自定义的meta对象,在meta对象中可以设置一些状态,供页面组件或者路由钩子函数中使用。
<body><div id="app"><div><router-link to="/login">登录</router-link><router-link to="/register">注册</router-link><keep-alive><router-view v-if="$route.meta.cache"></router-view></keep-alive><!-- 不缓存 --><router-view v-if="!$route.meta.cache"></router-view></div></div><script>var login = {template: '<h3>登录<input type="text"></h3>'}var register = {template: '<h3>注册<input type="text"></h3>'}var router = new VueRouter({routes: [{ path: '/login',component: login ,meta: {cache: false}},{ path: '/register',component: register,meta: {cache: true}}]})// 创建Vue实例得到ViewModelvar vm = new Vue({el: '#app',data: {},methods: {},router});</script></body>
四、子路由,路由重定向

五、keep-alive
keep-alive 包裹路由-组件。 缓存组件 之后组件不会被销毁 组件对应的几个生命周期函数不会重新触发

当组件在
<keep-alive>内被切换,它的activated和deactivated这两个生命周期钩子函数将会被对应执行5-1 解决mounted生命周期不执行的问题
第一种:在activated生命周期函数里面进行http请求

- 第二种:exclude
Tip:exclude绑定的组件不受keep-alive限制
//detail.vue页面1.exclude Tips:一定要给组件name属性export default {name: "Detail",data() {return {imgUrl: ""};},mounted() {...}};</script>//App.vue页面2.配置keep-alive<keep-alive exclude="Detail"><router-view /></keep-alive>
5-2 实现组件缓存功能
vue-cli工程中实现某个组件的缓存功能,可用 keep-alive 标签与 vue-router的meta形式数据传递配合完成。
//第一步:在 app.vue 里面 template部分 使用 <keep-alive></keep-alive> 组件:<template><div id="app"><keep-alive><router-view v-if="$router.meta.keepAlive"></router-view></keep-alive><router-view v-if="!$router.meta.keepAlive"></router-view></div></template>//第二步:在src/router.js:import account from '../page/demo/account.vue'import course from '../page/demo/course.vue'export default new Router({routes: [{path: '/account',name: 'account',component: Account,meta:{keepAlive:false //false为不缓存}},{path: '/course',name: 'course',component: course,meta:{keepAlive:true //true为缓存}}]})
六、命名路由
//配置{path: '/detail',/* 命名路由 */name: 'detail',component: () => import('../views/Detail.vue')}
6-1 router-link,get
<router-link :to="{name:'detail',query:{id:1213}}">detail</router-link>
6-2 router-link,动态路由
//配置动态路由{path: '/detail/:id',/* 命名路由 */name: 'detail',component: () => import('../views/Detail.vue')}//配置router-link<router-link :to="{name:'detail',params:{id:1213}}">detail</router-link>
6-3 $router.push()
this.$router.push({name:"detail",params:{id:1314}})
6-4 props解耦id
//配置路由{path: '/detail/:id',/* 命名路由 */name:'detail',component:() => import('../views/Detail.vue'),//core codeprops:true}
//Detail.vueexport default {props:['id'],mounted(){console.log(this.id)}};
七、路由守卫
7-1 全局守卫
router.beforeEach router.beforeResolve router.afterEach
import Vue from 'vue'import VueRouter from 'vue-router'Vue.use(VueRouter)'''const router = new VueRouter({mode: 'history',routes})router.beforeEach((to, from, next) => {//to 将要访问的路径//from 代表从哪个路径跳转而来//next 是一个函数,表示放行// next() 放行 next('/login') 强制跳转if (to.path === '/login') return next();//获取缓存const tokenStr = window.sessionStorage.getItem('token')//如果没有值,则强制跳转login页面,有则放行if (!tokenStr) return next('/login')next()})export default router
const router = new VueRouter({ ... });router.beforeEach((to, from, next) => {// do someting});//to:代表要进入的目标,它是一个路由对象//from:代表当前正要离开的路由,同样也是一个路由对象//next:这是一个必须需要调用的方法,而具体的执行效果则依赖 next 方法调用的参数//全局后置钩子,后置钩子并没有 next 函数,也不会改变导航本身router.afterEach((to, from) => {// do someting});
7-2 路由独享守卫
路由独享的守卫: beforeEnter
cont router = new VueRouter({routes: [{path: '/file',component: File,beforeEnter: (to, from ,next) => {// do someting}}]});
7-3 局部守卫(组件内守卫)
beforeRouteEnter、beforeRouteUpdate (2.2 新增)、beforeRouteLeave
const File = {template: `<div>This is file</div>`,beforeRouteEnter(to, from, next) {// do someting// 在渲染该组件的对应路由被 confirm 前调用},beforeRouteUpdate(to, from, next) {// do someting// 在当前路由改变,但是依然渲染该组件是调用},beforeRouteLeave(to, from ,next) {// do someting// 导航离开该组件的对应路由时被调用}}
进入/center路由模块之前如何没有登陆授权,则进入登陆页面
//Center.vueexport default {beforeRouteEnter(to,from,next){if(false){next()}else{next('/login')}}}
export default {beforeRouteEnter(to,from,next){//登陆成功则跳转if(true){next()}else{next('/login')}}}
路由守卫:主要就是全局守卫、路由独享守卫、局部守卫1、全局守卫:是指路由实例上直接操作的钩子函数,特点是所有路由配置的组件都会触发,直白点就是触发路由就会触发这些钩子函数router.beforeEach((to,from,next)=>{})回调函数中的参数,to:进入到哪个路由去,from:从哪个路由离开,next:函数,决定是否展示你要看到的路由页面2、路由独享守卫:是指在单个路由配置的时候也可以设置的钩子函数beforeEnter:(to,from,next)=>{}3、局部守卫:是指在组件内执行的钩子函数,类似于组件内的生命周期,相当于为配置路由的组件添加的生命周期钩子函数beforeRouteEnter:(to,from,next)=>{}
7-4 路由跳转导航解析流程
当由A路由 —> B路由的时候:
a、在A组件里调用离开守卫。 A组件中的 beforeRouteLeaveb、调用全局的 beforeEach 守卫。 router.beforeEachc、再执行B路由配置里调用 beforeEnter。routes: [{path: '/b',component: B,beforeEnter: (to, from, next) => {}}]d、再执行B组件的进入守卫。 B组件中 beforeRouteEnter。e、调用全局的 beforeResole 守卫 (2.5+)。 router.beforeResolvef、导航被确认。g、调用全局的 afterEach 钩子。 router.afterEachh、触发 DOM 更新。
7-4 例子
全局守卫:import Vue from 'vue'import VueRouter from 'vue-router'Vue.use(VueRouter)'''const router = new VueRouter({mode: 'history',routes})router.beforeEach((to, from, next) => {//to 将要访问的路径//from 代表从哪个路径跳转而来//next 是一个函数,表示放行// next() 放行 next('/login') 强制跳转if (to.path === '/login') return next();//获取缓存const tokenStr = window.sessionStorage.getItem('token')//如果没有值,则强制跳转login页面,有则放行if (!tokenStr) return next('/login')next()})export default routerCopy to clipboardErrorCopied
局部守卫:beforeRouteEnter不能获取组件实例"this",但我们通过传一个回调给next,就可以使用vm来访问组件实例<script>export default {data(){return{name:"Arya"}},beforeRouteEnter:(to,from,next)=>{next(vm=>{alert("hello" + vm.name);})}}</script>
