Vue-router 学习笔记

793 阅读7分钟
  1. router-link实现路由的跳转链接,更改url
  2. router-view 显示对用url的组件的具体内容、
  3. 通过定义App.use(router),我们就可以访问this.routerthis.router和this.route,以实现路由的跳转和路由参数的获取
  4. 要访问setup函数里的路由,需要预先调用userRouter和useRoute函数
    this.$router.push({
        name:'home',
        params: { pathMatch: this.$route.path.substring(1).split('/') },
        query: this.$route.query,
        hash: this.$route.hash
    })
  1. 路由匹配语法:
    const routes = {
        {path: '/:id +'}      ===> / ,/one, /one/two, /one/two/three
        {path: '/:id *'}      ===> /one, /one/two, /one/two/three
        {path: '/user/:id ?'} ===> /user或/user/23
    }

可重复参数时,比如:/first/second/third,可使用*(0或更多)、+(1或更多),将参数标记为可重复。 ? 是将参数标记为可选,但不能重复

  1. 嵌套路由:

    children是实现嵌套视图的路由数组。path为''时,可实现未定义的在空嵌套路由里实现匹配。

    const routes = {
        path:'/user/:id',
        component: User,
        children: [
            {
                path:'profile',
                component: UserProfile,
            },
            {
                path:'',
                component: UserHome,
            }
        ]
    }
  1. 程序化导航

导航方式有两种: 一是声明性导航的锚标记 二是程序化导航this.$router.push('...')

程序化导航的方式有几种:

 字符串路径:           this.$router.push('/user/profile')
 带有路径的对象:       this.$router.push({path:'/user/profile'})
 命名的路由,并带有参数:this.$router.push({name:'user',params:{id:'12'}})
 带有查询的参数:       this.$router.push({path:'/user',query:{id:'12'}})==> /user?id=12
 hash参数:            this.$router.push({name:'/user',hash:'#team'}) ==> /user#team

注意:带有params时,只能指定name,不能指定path,指定path的话,params参数会被忽略。

替换当前路由:

 this.$router.replace({path:'home'}) ===> this.$router.push({path:'home',repalce:true})

历史:在历史上前进后退的历史步。window.history.go(n);

 router.go(1) 等同于 router.forward() 向前移动一步。
 router.go(-1) 等同于 router.back() 返回一条记录。
 router.go(100) 前进100条记录,如果没有那么多记录,默默失败。
 
 router模仿了window.historyAPI。即:
 router.push === window.history.pushState
 router.replace === window.history.replaceState
 router.go === window.history.go
  1. 命名路线 除path外,增加name。
    const routes = [
        {
            path:'/user',
            name:'user',
            component:User
        }
    ]
  1. 命名视图:
    const routes = [
        {
            path:'/user',
            component:{
                default,
                LeftSidebar,  //与<router-link>里的name属性匹配
                RightSidebar
            }
        }
    ]
  1. 重定向和别名 redirect 实现路由的重定向:const routes = [{ path:'/home', redirect:'/'}] 指当用户访问 /home 时,URL 会被 / 替换,然后匹配成 /

alias实现别名:const routes = [{ path:'/', component:'homepage', alias:'/home'}] 当用户访问 /home 时,URL 仍然是 /home,但会被匹配为用户正在访问 /

  1. 路由组件传参 通过props传递参数给路由组件

 const routes = [
     { 
         path: '/user/:id', 
         component: User, 
         props: true    //布尔模式 props设置为true,通过this.$route.params 将被props 代替
         props: {default:true,sidebar:false}           //命名视图
         props: { newsletterPopup: false }             //对象模式 props是一个对象
         props: route => ({ query: route.query.q })    //函数模式
     }
 ]
  1. 不同的历史模式

hash模式是由createWebHashHistory()创建的,在URL中有#,但不利于SEO HTML5模式是由createWebHistory()创建的

14.导航守卫:

1.   全局导航守卫、路由独享导航守卫、组件级的导航守卫
2.   全局导航守卫分为:全局前置守卫beforeEach、全局解析守卫beforeResolve、全局后置钩子afterEach
3.   路由独享守卫分为:在路由配置里定义beforeEach
4.   组件内的守卫分为:可配置API(beforeRouteEnter/beforeRouteUpdate/beforeRouteLeave)、组合API(onBeforeRouteUpdate/onBeforeRouteLeave)
  • [1] 全局导航守卫

    1. 全局前置守卫:
    
    router.beforeEach接受两个参数:tofrom
    
    to:即将要进入的目标
    from:当前导航将要离开的路由
    
    返回值:
    
    false:取消当前的导航,或重置到from路由对应的地址
    一个路由地址:等同于router.push() 实现路由的跳转
    
    可选的第三个参数next:确保next在导航守卫中都被严格调用一次。
    
        用户未能验证身份重定向到login页面
         router.beforeEach((to,from,next)=>{
             if (to.name !== 'Login' && !isAuthenticated) next({ name: 'Login' })
             else next()
         })
    
    2. 全局解析守卫
    
      router.beforeResolve
      每次导航都会触发,被解析后,解析守卫被正确调用。可访问自定义的meta属性
      
    
    3.全局后置钩子
    
      router.afterEach和router.beforeEach不同的是,不接受next参数,接受一个failure参数。
      用于 分析、更改页面标题、声明页面等辅助功能。
    
      ```js
      router.afterEach((to,from)=>{
        if (!failure) sendToAnalytics(to.fullPath)
      })
    
      ```
    
  • [2] 路由独享守卫

beforeEach只在进入路由时触发,不会在params、query、hash时触发。 beforeEach也可以定义数组,实现不同的理由重用守卫。

    路由配置里定义beforeEach
    const routes = [
        {
            path:'/user',
            name: 'user',
            component:User,
            beforeEach:(to,from)=>{
                return false
            }
            beforeEach:[removeQueryParams,removeHash]
        }
    ]
    
  • [3] 组件内的守卫

     可用的配置API有:beforeRouteEnter、beforeRouteUpdate、beforeRouteLeave
     注意点是beforeRouteEnter可以用next参数,并且通过next参数可访问this实例,beforeRouteUpdate和beforeRouteLeave不可使用next参数,但可访问this实例。
    
     使用组合API有:onBeforeRouteUpdate、onBeforeRouteLeave
    
        const UserDetails = {
            template:'...',
            beforeRouteEnter(to,from,next){
                渲染该组件的路由被验证前调用
                next(vm=>{})
            },
            beforeRouteUpdate(to,from){
                当前路由改变,但当前组件复用时调用
            },
             beforeRouteLeave(to,from){
                当导航离开渲染该组件的对应路由时调用
            },
        }
    

15.完整的导航解析流程 12步

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

16. 路由元信息

meta可实现将信息附加到路由上,解决过渡名称、访问当前路由的权限等。路由地址和导航守卫都可访问到。 路由记录:routes配置中的每个路由对象为路由记录,若路由记录是嵌套的(有children),当一个路由匹配成功时,会匹配到多个路由记录。 this.route.matched数组和this.route.matched数组和this.route.meta来获取meta字段。

  1. 数据获取

导航完成后获取:在生命周期钩子中获取数据,created 导航完成前获取:在路由守卫中获取数据,beforeRouteEnter

  1. 过渡效果

transition 配合meta实现不同情况的过渡效果

  1. 滚动行为

这个功能只在支持history.pushState的浏览器中可用

    const router = createRouter({
        history:createWebHashHistory(),
        scrollbehaivor(to,from,savePosition){
            top:0;
        },
        routes:[...]
    })
  1. 路由懒加载

当打包构建应用时,JavaScript包会变得非常大,影响页面加载。 解决方案一:将不同路由对用的不同组件分割成不同的代码块,当路由被访问时才加载对应组件。用动态导入代替静态导入。

    静态导入:import UserDetails from './user/userDetails'
    动态导入:const UserDetails = ()=> import('./user/userDetails')

解决方案二:通过chunk命名,将所有组件都打包到同一个异步块中。

    在动态导入的基础上加入chunkName
    const UserDetails = ()=> import(/* webpackChunkName: "group-user" */,'./userDetails.vue')

  1. 导航故障

检测导航故障: navigationResult

    const navigationResult = await router.push('/home')

鉴别导航故障: isNavigationFailure、isNavigationFailureType 有三个不同的类型: aborted:在导航守卫中返回false中断了本次导航 cancelled:在导航还没有完成之前又有了新的导航。 duplicated:导航被阻止,已经在目标位置。

检测重定向: redirectedFrom

  1. 动态路由

    添加路由:router.addRoute

    router.addRoute({ path:'/about', component:About })
    

    删除路由:router.removeRoute

    router.removeRoute('about')
    

    添加嵌套路由

    router.addRoute({ name: 'admin', path: '/admin', component: Admin })
    router.addRoute('admin', { path: 'settings', component: AdminSettings })
    

    查看现有路由

    router.hasRoute() 检查路由是否存在 router.getRoutes() 获取一个包含所有路由记录的数组

  2. API to

```js
to表示目标路由的链接。to的值是目标位置的对象
<router-link to="/home">Home</router-link> 渲染成 <a herf="/home">Home</a>

replace代替router.push()。区别是不会留下历史记录,不能后退。
<router-link to="/abc" replace></router-link>

custom是否将router-link的值包裹在a元素中,默认值为false
<router-link to="/home" custom v-slot="{ navigate, href, route }">
  <a :href="href" @click="navigate">{{ route.fullPath }}</a>
</router-link>

active-class激活时的类
aria-current-value 激活时传给aria-current的值,默认值page
exact-active-class 链接精准激活时的类
name 可渲染对应的路由配置中component下的对应组件
createRouter是创建一个路由实例。接受一个routerOptions对象,表示可传递的属性列表
createWebHistory 创建一个HTML5的history的模式,接受可选参数base,必须使用http协议提供服务,file:/// 不可以。
createWebHashHistory 创建一个带#的hash历史记录,适合没有主机的应用程序file:/// 或配置服务器不能使用URL时。但是不利于SEO。(如果在 base 中提供了 `#`,则它不会被 `createWebHashHistory` 添加)
createWebHashHistory('/folder/#/app/') // 给出的网址为 `https://example.com/folder/#/app/`
// at file:///usr/etc/folder/index.html
// 对于没有 `host` 的位置,base被忽略
createWebHashHistory('/iAmIgnored') // 给出的网址为 `file:///usr/etc/folder/index.html#`
creatememoryHistory  创建一个基于内存的历史记录
NavigationFailureType 导航失败的类型,有三个属性,aborted(4)、cancelled(8)、duplicated(16)
onBeforeRouteLeave 组件导航守卫 离开组件时触发,组件被卸载,导航守卫移除
onBeforeRouteUpdate 组件导航守卫 当前置为即将更新时触发
useLink v-slot API暴露的内容
useRoute 返回路由地址信息 必须在setUp中使用
useRouter 路由导航 必须在setUp中使用
addRoute 添加一条新的理由记录作为当前路由的子路由,若name存在,则删除之前的name。
afterEach 添加一个导航钩子,导航后执行。
beforeEach 添加一个导航守卫,在任何导航前执行。
beforeResolve 添加一个导航守卫,在导航即将解析之前执行
back history.back() 等同于 router.go(-1)
forward history.forward() 等同于 router.go(1)
getRoutes 获取路由记录的完整列表
hasRoute 确认是否存在指定名称的路由
removeRoute 通过名称删除现有导航
repalce 替换历史堆栈中的当前entry,导航到一个新的url
push  通过在历史堆栈中推送一个entry,导航到一个新的url
name 路由记录里独一无二的名称
fullPath URl编码与路由地址有关,包括path、query、hash
matched 路由记录数组
```

应用

vue权限路由实现:

  1. 菜单与路由分离,菜单由后端返回

    菜单的管理是由后端控制的,比如新添加的菜单名称,菜单图标,都是后端管理的,在数据库里配置。 由于name是路有记录里独一无二的名称,作为路由和菜单匹配的唯一key。

    {
       name:'login',
       path:'/login',
       component:r => require.ensure([], () => r(require('views/base/Login')), 'Login')
    }
    

    注意点:必须定义name,为了和后端返回的路由菜单关联。 后端返回的是一个当前登录人具有权限的菜单名称的数组:['home','finace','leader']

    1、在登录的时候通过接口获取到后端返回的当前登录人的菜单名称数组,然后放在sessionStorage里面 2、全局导航守卫 每次路由跳转都会进行导航守卫判断

    
    router.beforeEach((to,from,next)=>{
      //先获取缓存里的菜单数组
      let menuArray = JSON.parse(sessionStorage.getItem('menuArray'))
      //判断当前用户有没有可用的菜单数组,有则是通过登录页面进入系统
      if(menuArray && menuArray.lengh){
          //如果要进入的路由在菜单数组内,或者meta标签下的faName在菜单数组内,则进入
          /faName 是name里的关系页面,比如一个查询页面,它的详情页的faName就是查询页面的路由名称
          if(menuArray.indexOf(to.name) !== -1 || menuArray.indexOf(to.meta.faName) !== -1){
              next()
          }else{
              next('/error')
          }
          
      }else{
          //没有当前系统的菜单、若是免登录白名单
          //跳转到对应的页面,可以显示
          if(to.name === 'publicPage'){
              next()
          }
          //如果跳转到的路由是home
          else if(to.name === 'home'){
              //判断是否是单点登录,有token就跳
              if(to.query.token){
                  next()
              }else {
              //如果没有token,则不是单点登录,跳error页面
                  next('/error')
              }
          }else{
              //既不是公共页面,又不是单点登录页面,就跳到error页面
              next('/error')
          }
      }
    
    
    })
    
    
  2. 采用的认证机制:JWT(Json Web Token) 鉴权机制

    JWT的组成 = 头信息(header) + 消息体(payload) + 签名(signature) 头信息:包含JWT的签名算法 消息体:包含JWT主要信息,比如过期时间,用户主要信息 签名:确保信息数据不被篡改

  3. 前后端还有一套权限控制的设计。即用户管理和权限管理。 具体实现:给用户配角色,每个角色对应不同的菜单,根据用户的角色去控制实现菜单权限。 业务人、财务、管理员、执行人。