前言:什么是路由

1.对于普通的网站,所有的超链接都是URL地址,所有的URL地址都对应服务器上对应的资源;

  1. A : http://127.0.0.1:5500/12.路由的使用.html/register
  2. B : http://127.0.0.1:5500/12.路由的使用.html/login
  3. app.get("/login",(req,res)=>{})
  4. app.get("/register",(req,res)=>{})
  5. 当我们的网址由AB的时候,此时会向服务器发送请求(也就是此时服务器要处理login请求)

2.对于单页面应用程序来说,主要通过URL中的hash(#号)来实现不同页面之间的切换,同时hash有一个特点,HTTP请求中不会包含hash相关的内容

  1. A : http://127.0.0.1:5500/12.路由的使用.html#/register
  2. B : http://127.0.0.1:5500/12.路由的使用.html#/login
  3. 当我们的网址由AB的时候,此时网址中变化是#后面的内容,此时不会向服务器发送请求。这种方式我们称为前端路由。
  4. 当我们由#/register切换到#/login变化的是:当前的路由地址所对应的组件信息

3.在单页面应用程序中,这种通过hash改变来切换页面的方式,称作前端路由(区别于后端路由);

一、路由配置

1-1 安装依赖

  1. yarn add vue-router

1-2 在App.vue

  1. <template>
  2. <div id="app">
  3. <router-view></router-view>
  4. </div>
  5. </template>

1-3 在routers文件夹下

  1. //index.js
  2. import Vue from 'vue';
  3. import Router from 'vue-router'
  4. import Music from '@/pages/Music.vue'
  5. import Mv from '@/pages/Mv.vue'
  6. Vue.use(Router);
  7. export default new Router({
  8. mode:"hash", //history
  9. routes:[
  10. {
  11. path:'/music',
  12. name:"music",
  13. component:Music
  14. },
  15. {
  16. path:'/mv',
  17. name:"mv",
  18. component:Mv
  19. }
  20. ]
  21. })

1-3-1 异步路由

  • 进入页面时才会触发路由

    1. export default new Router({
    2. mode:"hash",
    3. routes:[
    4. ...
    5. {
    6. path:"/detail",
    7. name:"detail",
    8. /* 异步路由 */
    9. component:()=>import('@/pages/Detail')
    10. }
    11. ]
    12. })

1-4 在main.js下

  1. import router from './routers'
  2. Vue.config.productionTip = false
  3. new Vue({
  4. router,
  5. render: h => h(App),
  6. }).$mount('#app')

二、router-link 切换组件

  1. //App.vue下
  2. <template>
  3. <div id="app">
  4. <div id="nav">
  5. <router-link to="/music">音乐</router-link>
  6. <router-link to="/mv">MV</router-link>
  7. </div>
  8. <router-view></router-view>
  9. </div>
  10. </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 动态路由

  1. 传参:
  2. <router-link :to="'/detail/'+item.id" tag="button">
  3. 跳转到detail
  4. </router-link>
  5. 接收传参:
  6. this.$route.params.id;

router配置
image.png
主页
image.png
详情页
image.png

3-2 get传值

3-2-1 在列表页传值this.$router.push()

  1. <div @click="handleClick(data.id)"></div>
  1. <router-link :to=`/detail?id=${id}` tag="button">
  2. 跳转到detail
  3. </router-link>
  1. export default {
  2. name:"Item",
  3. props:{
  4. data:{
  5. type:Object,
  6. required:true
  7. }
  8. },
  9. methods:{
  10. handleClick(id){
  11. console.log(id)
  12. this.$router.push(`/detail?id=${id}`)
  13. }
  14. }
  15. };

3-2-2 在详情页接收值this.$route.query

  1. export default {
  2. name:"Detail",
  3. computed:{
  4. id(){
  5. return this.$route.query.id
  6. }
  7. }
  8. };
  1. mouted(){
  2. var id = this.$route.query.id
  3. }

3-2-3 在详情页跳转回列表页

  1. methods: {
  2. toggle() {
  3. this.$router.back();
  4. }
  5. }

3-3 关于路由跳转

3-3-1 router-link方式

不带参数:

  1. <router-link :to="{name:'home'}">

带参数:params传参数

  1. html 取参 $route.params.id
  2. script 取参 this.$route.params.id
  3. <router-link :to="{name:'home', params: {id:1}}">

带参数:query传参数 (类似get,url后面会显示参数)

  1. 注意点:如果使用pathname不可以和params共用
  2. html 取参 $route.query.id
  3. script 取参 this.$route.query.id
  4. <router-link :to="{name:'home', query: {id:1}}">

3-3-2 this.$router.push() 编程式导航

不带参数:

  1. this.$router.push('/home')
  2. this.$router.push({name:'home'})
  3. this.$router.push({path:'/home'})

query传参:

  1. this.$router.push({name:'home',query: {id:'1'}})
  2. this.$router.push({path:'/home',query: {id:'1'}})

params传参:
params只能用name来引入路由,不能与path一起用

  1. 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对象中可以设置一些状态,供页面组件或者路由钩子函数中使用。

  1. <body>
  2. <div id="app">
  3. <div>
  4. <router-link to="/login">登录</router-link>
  5. <router-link to="/register">注册</router-link>
  6. <keep-alive>
  7. <router-view v-if="$route.meta.cache"></router-view>
  8. </keep-alive>
  9. <!-- 不缓存 -->
  10. <router-view v-if="!$route.meta.cache"></router-view>
  11. </div>
  12. </div>
  13. <script>
  14. var login = {
  15. template: '<h3>登录<input type="text"></h3>'
  16. }
  17. var register = {
  18. template: '<h3>注册<input type="text"></h3>'
  19. }
  20. var router = new VueRouter({
  21. routes: [
  22. { path: '/login',
  23. component: login ,
  24. meta: {
  25. cache: false
  26. }
  27. },
  28. { path: '/register',
  29. component: register,
  30. meta: {
  31. cache: true
  32. }
  33. }
  34. ]
  35. })
  36. // 创建Vue实例得到ViewModel
  37. var vm = new Vue({
  38. el: '#app',
  39. data: {},
  40. methods: {},
  41. router
  42. });
  43. </script>
  44. </body>

四、子路由,路由重定向

image.png

五、keep-alive

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

image.png

  • 当组件在 <keep-alive> 内被切换,它的 activateddeactivated 这两个生命周期钩子函数将会被对应执行

    5-1 解决mounted生命周期不执行的问题

  • 第一种:在activated生命周期函数里面进行http请求

image.png

  • 第二种:exclude

Tip:exclude绑定的组件不受keep-alive限制

  1. //detail.vue页面
  2. 1.exclude Tips:一定要给组件name属性
  3. export default {
  4. name: "Detail",
  5. data() {
  6. return {
  7. imgUrl: ""
  8. };
  9. },
  10. mounted() {
  11. ...
  12. }
  13. };
  14. </script>
  15. //App.vue页面
  16. 2.配置keep-alive
  17. <keep-alive exclude="Detail">
  18. <router-view />
  19. </keep-alive>

5-2 实现组件缓存功能

vue-cli工程中实现某个组件的缓存功能,可用 keep-alive 标签与 vue-router的meta形式数据传递配合完成。

  1. //第一步:在 app.vue 里面 template部分 使用 <keep-alive></keep-alive> 组件:
  2. <template>
  3. <div id="app">
  4. <keep-alive>
  5. <router-view v-if="$router.meta.keepAlive"></router-view>
  6. </keep-alive>
  7. <router-view v-if="!$router.meta.keepAlive"></router-view>
  8. </div>
  9. </template>
  10. //第二步:在src/router.js:
  11. import account from '../page/demo/account.vue'
  12. import course from '../page/demo/course.vue'
  13. export default new Router({
  14. routes: [
  15. {
  16. path: '/account',
  17. name: 'account',
  18. component: Account,
  19. meta:{
  20. keepAlive:false //false为不缓存
  21. }
  22. },
  23. {
  24. path: '/course',
  25. name: 'course',
  26. component: course,
  27. meta:{
  28. keepAlive:true //true为缓存
  29. }
  30. }
  31. ]
  32. })

六、命名路由

  1. //配置
  2. {
  3. path: '/detail',
  4. /* 命名路由 */
  5. name: 'detail',
  6. component: () => import('../views/Detail.vue')
  7. }

6-1 router-link,get

  1. <router-link :to="{name:'detail',query:{id:1213}}">detail</router-link>

6-2 router-link,动态路由

  1. //配置动态路由
  2. {
  3. path: '/detail/:id',
  4. /* 命名路由 */
  5. name: 'detail',
  6. component: () => import('../views/Detail.vue')
  7. }
  8. //配置router-link
  9. <router-link :to="{name:'detail',params:{id:1213}}">detail</router-link>

6-3 $router.push()

  1. this.$router.push({name:"detail",params:{id:1314}})

6-4 props解耦id

  1. //配置路由
  2. {
  3. path: '/detail/:id',
  4. /* 命名路由 */
  5. name:'detail',
  6. component:() => import('../views/Detail.vue'),
  7. //core code
  8. props:true
  9. }
  1. //Detail.vue
  2. export default {
  3. props:['id'],
  4. mounted(){
  5. console.log(this.id)
  6. }
  7. };

七、路由守卫

7-1 全局守卫

router.beforeEach router.beforeResolve router.afterEach
image.png

  1. import Vue from 'vue'
  2. import VueRouter from 'vue-router'
  3. Vue.use(VueRouter)
  4. '''
  5. const router = new VueRouter({
  6. mode: 'history',
  7. routes
  8. })
  9. router.beforeEach((to, from, next) => {
  10. //to 将要访问的路径
  11. //from 代表从哪个路径跳转而来
  12. //next 是一个函数,表示放行
  13. // next() 放行 next('/login') 强制跳转
  14. if (to.path === '/login') return next();
  15. //获取缓存
  16. const tokenStr = window.sessionStorage.getItem('token')
  17. //如果没有值,则强制跳转login页面,有则放行
  18. if (!tokenStr) return next('/login')
  19. next()
  20. })
  21. export default router
  1. const router = new VueRouter({ ... });
  2. router.beforeEach((to, from, next) => {
  3. // do someting
  4. });
  5. //to:代表要进入的目标,它是一个路由对象
  6. //from:代表当前正要离开的路由,同样也是一个路由对象
  7. //next:这是一个必须需要调用的方法,而具体的执行效果则依赖 next 方法调用的参数
  8. //全局后置钩子,后置钩子并没有 next 函数,也不会改变导航本身
  9. router.afterEach((to, from) => {
  10. // do someting
  11. });

7-2 路由独享守卫

路由独享的守卫: beforeEnter

  1. cont router = new VueRouter({
  2. routes: [
  3. {
  4. path: '/file',
  5. component: File,
  6. beforeEnter: (to, from ,next) => {
  7. // do someting
  8. }
  9. }
  10. ]
  11. });

7-3 局部守卫(组件内守卫)

beforeRouteEnter、beforeRouteUpdate (2.2 新增)、beforeRouteLeave

  1. const File = {
  2. template: `<div>This is file</div>`,
  3. beforeRouteEnter(to, from, next) {
  4. // do someting
  5. // 在渲染该组件的对应路由被 confirm 前调用
  6. },
  7. beforeRouteUpdate(to, from, next) {
  8. // do someting
  9. // 在当前路由改变,但是依然渲染该组件是调用
  10. },
  11. beforeRouteLeave(to, from ,next) {
  12. // do someting
  13. // 导航离开该组件的对应路由时被调用
  14. }
  15. }

进入/center路由模块之前如何没有登陆授权,则进入登陆页面

  1. //Center.vue
  2. export default {
  3. beforeRouteEnter(to,from,next){
  4. if(false){
  5. next()
  6. }else{
  7. next('/login')
  8. }
  9. }
  10. }
  1. export default {
  2. beforeRouteEnter(to,from,next){
  3. //登陆成功则跳转
  4. if(true){
  5. next()
  6. }else{
  7. next('/login')
  8. }
  9. }
  10. }

文档
文档

  1. 路由守卫:主要就是全局守卫、路由独享守卫、局部守卫
  2. 1、全局守卫:是指路由实例上直接操作的钩子函数,特点是所有路由配置的组件都会触发,直白点就是触发路由就会
  3. 触发这些钩子函数
  4. router.beforeEach((to,from,next)=>{})
  5. 回调函数中的参数,to:进入到哪个路由去,from:从哪个路由离开,next:函数,决定是否展示你要看到的
  6. 路由页面
  7. 2、路由独享守卫:是指在单个路由配置的时候也可以设置的钩子函数
  8. beforeEnter:(to,from,next)=>{}
  9. 3、局部守卫:是指在组件内执行的钩子函数,类似于组件内的生命周期,相当于为配置路由的组件添加的生命周期钩
  10. 子函数
  11. beforeRouteEnter:(to,from,next)=>{}

7-4 路由跳转导航解析流程

当由A路由 —> B路由的时候:

  1. a、在A组件里调用离开守卫。 A组件中的 beforeRouteLeave
  2. b、调用全局的 beforeEach 守卫。 router.beforeEach
  3. c、再执行B路由配置里调用 beforeEnter
  4. routes: [
  5. {
  6. path: '/b',
  7. component: B,
  8. beforeEnter: (to, from, next) => {
  9. }
  10. }
  11. ]
  12. d、再执行B组件的进入守卫。 B组件中 beforeRouteEnter
  13. e、调用全局的 beforeResole 守卫 (2.5+)。 router.beforeResolve
  14. f、导航被确认。
  15. g、调用全局的 afterEach 钩子。 router.afterEach
  16. h、触发 DOM 更新。

7-4 例子

  1. 全局守卫:
  2. import Vue from 'vue'
  3. import VueRouter from 'vue-router'
  4. Vue.use(VueRouter)
  5. '''
  6. const router = new VueRouter({
  7. mode: 'history',
  8. routes
  9. })
  10. router.beforeEach((to, from, next) => {
  11. //to 将要访问的路径
  12. //from 代表从哪个路径跳转而来
  13. //next 是一个函数,表示放行
  14. // next() 放行 next('/login') 强制跳转
  15. if (to.path === '/login') return next();
  16. //获取缓存
  17. const tokenStr = window.sessionStorage.getItem('token')
  18. //如果没有值,则强制跳转login页面,有则放行
  19. if (!tokenStr) return next('/login')
  20. next()
  21. })
  22. export default routerCopy to clipboardErrorCopied
  1. 局部守卫:beforeRouteEnter不能获取组件实例"this",但我们通过传一个回调给next,就可以使用vm来访问组件实例
  2. <script>
  3. export default {
  4. data(){
  5. return{
  6. name:"Arya"
  7. }
  8. },
  9. beforeRouteEnter:(to,from,next)=>{
  10. next(vm=>{
  11. alert("hello" + vm.name);
  12. })
  13. }
  14. }
  15. </script>