【Vue】vue-router学习笔记

一、一些概念

1.什么是vue-router

路由模块的本质:建立起url和页面之间的映射关系

2.实现原理

单页面应用(SPA)的核心之一是: 更新视图而不重新请求页面;
vue-router在实现单页面前端路由时,提供了两种方式:Hash模式和History模式;根据mode参数来决定采用哪一种方式。

Hash模式

vue-router 默认 hash 模式 ,hash - 即地址栏URL中的 # 符号(此hash不是密码学里的散列运算)
比如这个URL:http://www.abc.com/#/hello,hash的值为#/hello.它的特点在于:hash虽然出现在URL中,但不会被包括在HTTP请求中,对后端完全没有影响,因此改变hash不会重新加载页面

History模式

利用了 HTML5 History Interface 中新增的 pushState() 和 replaceState() 方法。(需要特定浏览器支持)这两个方法应用于浏览器的历史记录栈,在当前已有的 back、forward、go 的基础之上,它们提供了对历史记录进行修改的功能。只是当它们执行修改时,虽然改变了当前的 URL,但浏览器不会立即向后端发送请求

使用场景

一般场景下,hash 和 history 都可以,除非你更在意颜值,# 符号夹杂在 URL 里看起来确实有些不太美观。

3.使用方式

  • 方式1:直接修改地址栏
  • 方式2:this.$router.push(‘路由地址’)
  • 方式3:<router-link to="路由地址"></router-link>

二、vue-router使用方式

1:下载 npm i vue-router -S
2:在main.js中引入 import VueRouter from ‘vue-router’;
3:安装插件Vue.use(VueRouter);
4:创建路由对象并配置路由规则 let router = new VueRouter({routes:[{path:’/home’,component:Home}]});
5:将其路由对象传递给Vue的实例,options中加入 router:router
6:在app.vue中留坑 <router-view></router-view>
案例详细步骤:
在这里插入图片描述

vue-router配置子路由(二级路由)

H1页面和H2页面嵌套在主页中,如下:
在这里插入图片描述在这里插入图片描述
1.首先用<router-link>标签增加了两个新的导航链接

<router-link :to="{name:'HelloWorld'}">主页</router-link>
<router-link :to="{name:'H1'}">H1页面</router-link>
<router-link :to="{name:'H2'}">H2页面</router-link>

2.在HelloWorld.vue加入<router-view>标签,给子模板提供插入位置

 <template>
  <div class="hello">
    <h1>{{ msg }}</h1>
    <router-view></router-view>
  </div>
</template>

3.在components目录下新建两个组件模板 H1.vue 和 H2.vue
两者内容类似,以下是H1.vue页面内容:

 <template>
  <div class="hello">
    <h1>{{ msg }}</h1>
  </div>
</template>
<script>
  export default {
    data() {
      return {
        msg: 'I am H1 page,Welcome to H1'
      }
    }
  }
</script>

4.修改router/index.js代码,子路由的写法是在原有的路由配置下加入children字段。

   routes: [
    {
      path: '/',
      name: 'HelloWorld',
      component: HelloWorld,
      children: [{path: '/h1', name: 'H1', component: H1},//子路由的<router-view>必须在HelloWorld.vue中出现
        {path: '/h2', name: 'H2', component: H2}
      ]
    }
  ]

三、$router常见跳转方法

<button @click="goToMenu" class="btn btn-success">Let's order!</button>
.....
<script>
  export default{
    methods:{
      goToMenu(){
        this.$router.go(-1)//跳转到上一次浏览的页面
        this.$router.replace('/menu')//指定跳转的地址
        this.$router.replace({name:'menuLink'})//指定跳转路由的名字下
        this.$router.push('/menu')//通过push进行跳转
        this.$router.push({name:'menuLink'})//通过push进行跳转路由的名字下
      }
    }
  }
</script>

PS:$router.push$router.replace的区别:

  • 使用push方法的跳转会向 history 栈添加一个新的记录,当我们点击浏览器的返回按钮时可以看到之前的页面。
  • 使用replace方法不会向 history 添加新记录,而是替换掉当前的 history 记录,即当replace跳转到的网页后,‘后退’按钮不能查看之前的页面。

四、导航守卫

1.导航守卫钩子

导航守卫的用途主要是在用户离开页面前提醒用户,和页面访问前先登录。
共有三类守卫:全局守卫,路由独享的守卫,组件内的守卫

1) 全局守卫

用来监测所有的路由,代码写在路由页面(router.js)

const router = new VueRouter({ ... })
router.beforeEach((to, from, next) => {
	// ...(2)
    //全局前置守卫
})
router.beforeResolve((to, from, next) => {
    // ...(6)
    //全局解析守卫
})
router.afterEach((to, from) => {
  	// ...(7)
  	//全局后置守卫
}
2)路由独享守卫

就是将路由钩子函数写在我们的某个具体路由对象里面:

const router = new VueRouter({
  routes: [
    {
      path: '/foo',
      component: Foo,
      beforeEnter: (to, from, next) => {
		// ...(4)
      }
    }
  ]
})
3)组件内的守卫
export default {
  data(){},
  beforeRouteEnter (to, from, next) {
  	//....(5)
    // 在渲染该组件的对应路由被 confirm 前调用
    // 不!能!获取组件实例 `this`
    // 因为当守卫执行前,组件实例还没被创建
    // 但是通过传一个回调给 next 来访问组件实例
  },
  beforeRouteUpdate (to, from, next) {
  	//....(3)
    // 在当前路由改变,但是该组件被复用时调用
    // 举例来说,对于一个带有动态参数的路径 /foo/:id,在 /foo/1 和 /foo/2 之间跳转的时候,
    // 由于会渲染同样的 Foo 组件,因此组件实例会被复用。而这个钩子就会在这个情况下被调用。
    // 可以访问组件实例 `this`
  },
  beforeRouteLeave (to, from, next) {
  	//....(1)
    // 导航离开该组件的对应路由时调用
    // 可以访问组件实例 `this`
  }
}

2.参数解析

to,from,next三个参数都是必要的
to:即将要进入的目标 路由对象
from:当前导航正要离开的路由
next:一定要调用该方法来 resolve 这个钩子,如果不写next()或者next(false),页面路由不会跳转,也就是页面被阻止在当前页面了

对于 next 也可以进行重定向到其他页面

next({ path:'/login' })
next('/login')
// 设置replace:true,导航不会留下历史记录
next({ ...to, replace: true })

to,from是一个对象,就是 routes[] 数组里面配置的某个具体的路由对象,
比如:to.path, to,name, to.meta 或 from.path, from.name, from.meta 【path,name,meta】这些字段都是自己在路由里面定义的字段,这样就可以开始写逻辑了。

3.整个过程

官网整个路由守卫被触发流程的步骤:

  1. 导航被触发。
  2. 在失活的组件里调用离开守卫。
  3. 调用全局的 beforeEach 守卫。
  4. 在重用的组件里调用 beforeRouteUpdate 守卫 (2.2+)。
  5. 在路由配置里调用 beforeEnter。
  6. 解析异步路由组件。
  7. 在被激活的组件里调用 beforeRouteEnter。
  8. 调用全局的 beforeResolve 守卫 (2.5+)。
  9. 导航被确认。
  10. 调用全局的 afterEach 钩子。
  11. 触发 DOM 更新。
  12. 用创建好的实例调用 beforeRouteEnter 守卫中传给 next 的回调函数。

4.举个栗子

要求:
1.列举需要判断登录状态的“路由集合”,当跳转至集合中的路由时,如果“未登录状态”,则跳转到登录页面LoginPage;
2.当直接进入登录页面LoginPage时,如果“已登录状态”,则跳转到首页HomePage;

import Vue from 'vue'
import Router from 'vue-router'
import Index from '@/components/index'
import Login from '@/components/login'
import Table from '@/components/table'
import Tabs from '@/components/tabs'
import Charts from '@/components/echarts'
import Vuex from '@/components/Vuex'
import Element from '@/components/Element'
import Error from '@/components/Error'
 
Vue.use(Router);
 
const router = new Router({
  routes: [
    {
      path: '/',
      redirect: '/index',
      meta: {
        requireAuth: true
      }
    },
    {
      path: '/login',
      component: Login,
      name: 'login'
    },
    {
      path: '/index',
      component: Index,
      name: 'index',
      meta: {
        requireAuth: true
      },
      children: [
        {
          path: 'table',
          component: Table,
          name: 'table',
          meta: {
            requireAuth: true
          }
        },
        {
          path: 'tabs',
          component: Tabs,
          name: 'tabs',
          meta: {
            requireAuth: true
          }
        }
        }
      ]
    },
    {
      path: '*',
      component: Error,
      name: 'error'
    }
  ]
});
 
export default router
 
router.beforeEach((to, from, next) => {
  if (to.meta.requireAuth) { // 判断该路由是否需要登录权限
    if (sessionStorage.getItem("token") == 'true') { // 判断本地是否存在token
      next()
    } else {
      // 未登录,跳转到登陆页面
      next({
        path: '/login'
      })
    }
  } else {
    if(sessionStorage.getItem("token") == 'true'){
      next('/index/table');
    }else{
      next();
    }
  }
});

Login不要添加

meta: {
        requireAuth: true
      }

否认会进入死循环。

另外一个例子

// main.js
import Vue from 'vue'
import ElementUI from 'element-ui'
import 'element-ui/lib/theme-chalk/index.css'
import App from './App'
import router from './router'
import mavonEditor from 'mavon-editor'
import 'mavon-editor/dist/css/index.css'
import 'echarts/theme/macarons.js'
import store from './store'
import NavMenu from '@/components/common/NavMenu'

var axios = require('axios')

// 使请求带上凭证信息
axios.defaults.withCredentials = true

Vue.prototype.$axios = axios
Vue.config.productionTip = false
Vue.use(ElementUI)
Vue.use(mavonEditor)

Vue.component('NavMenu', NavMenu)

// 如果前端没有登录信息则直接拦截,如果有则判断后端是否正常登录(防止构造参数绕过)
router.beforeEach((to, from, next) => {
    if (store.state.user.username && to.path.startsWith('/admin')) {
      axios.get('/authentication').then(resp => {
        initAdminMenu(router, store)
      })
    }
    if (to.meta.requireAuth) {
      if (store.state.user.username) {
        axios.get('/authentication').then(resp => {
          if (resp) next()
        })
      } else {
        next({
          path: 'login',
          query: {redirect: to.fullPath} //将目的路由地址存入login的query中
        })
      }
    } else {
      next()
    }
  }
)

参考:
路由守卫:
https://www.cnblogs.com/minigrasshopper/p/7928311.html
https://blog.csdn.net/lucky541788/article/details/91126602

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值