前端vue入门(纯代码)35_导航守卫

星光不问赶路人,时光不负有心人

33.Vue Router--导航守卫

导航守卫

正如其名,vue-router 提供的导航守卫主要用来通过跳转或取消的方式守卫导航。有多种机会植入路由导航过程中:全局的, 单个路由独享的, 或者组件级的。

记住参数或查询的改变并不会触发进入/离开的导航守卫。你可以通过观察 $route 对象来应对这些变化,或使用 beforeRouteUpdate 的组件内守卫。

全局前置守卫

你可以使用 router.beforeEach 注册一个全局前置守卫:

const router = new VueRouter({ ... })

//全局前置守卫
router.beforeEach((to,from,next) =>{
  //第一个参数to,包含的内容是切换后的路由对象,也就是跳转后的路由对象
  //第二个参数from,包含的内容的是切换前的路由对象,也就是跳转前的路由对象
  //第三个参数next(),是否往下执行,执行的话,如果不写的话路由就不会跳转,操作将会终止
    console.log('前置路由守卫',to,from,next)  
})

当一个导航触发时,全局前置守卫按照创建顺序调用。守卫是异步解析执行,此时导航在所有守卫 resolve【解析】 完之前一直处于 等待中

① 执行时间
初始化时执行,每次路由切换前执行
② 使用场景
全局前置守卫通常用来进行路由跳转的一些信息判断,判断是否登录,是否拿到对应的路由权限等等。

每个守卫方法接收三个参数:

  • to: Route: 即将要进入的目标路由对象
  • from: Route: 当前导航正要离开的路由
  • next: Function: 一定要调用该方法来 resolve 这个钩子。执行效果依赖 next 方法的调用参数。【进行下一个路由】
    • next(): 进行管道中的下一个钩子。如果全部钩子执行完了,则导航的状态就是 confirmed (确认的)。
    • next(false): 中断当前的导航。如果浏览器的 URL 改变了 (可能是用户手动或者浏览器后退按钮),那么 URL 地址会重置到 from 路由对应的地址。
    • next('/') 或者 next({ path: '/' }): 跳转到一个不同的地址。当前的导航被中断,然后进行一个新的导航。你可以向 next 传递任意位置对象,且允许设置诸如 replace: truename: 'home' 之类的选项以及任何用在 router-linkto prop或 router.push 中的选项。
    • next(error): (2.4.0+) 如果传入 next 的参数是一个 Error 实例,则导航会被终止且该错误会被传递给 router.onError() 注册过的回调。

确保 next 函数在任何给定的导航守卫中都被严格调用一次。它可以出现多于一次,但是只能在所有的逻辑路径都不重叠的情况下,否则钩子永远都不会被解析或报错。这里有一个在用户未能验证身份时重定向到 /login 的示例:

// BAD  错误示范
router.beforeEach((to, from, next) => {
  if (to.name !== 'Login' && !isAuthenticated) next({ name: 'Login' })
  // 如果用户未能验证身份,则 `next` 会被调用两次
  next()
})
// GOOD  推荐写法
router.beforeEach((to, from, next) => {
  if (to.name !== 'Login' && !isAuthenticated) next({ name: 'Login' })
  else next()
})

route/index.js

// 该文件专门用于创建整个应用的路由器
import VueRouter from 'vue-router';
//引入组件
import About from '../pages/About';
import Home from '../pages/Home';
import Cartoon from '../pages/Cartoon';
import Stars from '../pages/Stars';
import Detail from '../pages/Detail';

//创建并暴露一个路由器
const router = new VueRouter({
  // 定义一些路由
  // 每个路由都需要映射到一个组件。
  routes: [
	//配置路由路径和路由组件
	{
	  name: 'firstabout',
	  path: '/about',
	  component: About, //要跳转到的组件
      meta:{title:'关于'}
	},
	{
	  //一级路由配置
      name: 'firsthome',
	  path: '/home',
	  component: Home,
      meta:{title:'主页'},
	  children: [
		{
		  //二级路由配置
		  name: 'Hcartoon',
		  path: 'cartoon',
		  component: Cartoon,
          meta:{isAuth: true,title:'卡通'},
		},
		{
		  //二级路由配置
          name:'secondstars',
		  path: 'stars',
		  component: Stars,
          meta:{isAuth: true,title:'明星'},
		  children: [
			{
              //三级路由配置
              name: 'xiangqing',
              /*使用占位符声明,接收params参数,相当于说先占个位置,在路由组件中就可以按照位置进行参数传递*/
              // params方法传参配置
              // path: 'detail/:title/:works',
              // query方法传参配置
              path: 'detail',
              component: Detail,
              meta:{isAuth: true,title:'详情'},
			  //props的第三种写法,props值为函数,该函数返回的对象中每一组key-value都会通过props传给路由组件
			  // query方法传参配置
			  props($route) {
				return {
                    // works: $route.params.works,
                    title: $route.query.title,
                    works: $route.query.works,
                    a: 1,
                    b: 'hello',
                };
			  },
                // params方法传参配置
                /* props($route) {
                    return {
                       works: $route.params.works,
                       title: $route.params.title,
                       a:1,
                       b:'hello'
                    };
                }, */
			},
		  ],
		  },
		],
		},
	],
});

//全局前置路由守卫————初始化的时候被调用、每次路由切换之前被调用
router.beforeEach((to,from,next)=>{
  console.log('前置路由守卫',to,from)
  console.log('next函数',next)
   //判断是否需要鉴权
  if (to.meta.isAuth) {
    if (localStorage.getItem('userName') === 'xujianfei') {
      document.title =  to.meta.title
      next()
    }else{
      alert('用户名不对,无权限查看!')
    }
  }else{
    document.title =  to.meta.title
    next()
  }
})

export default router

全局后置钩子

  • 你也可以注册全局后置钩子,然而和守卫不同的是,这些钩子不会接受 next 函数也不会改变导航本身:

  • 全局后置守卫,组件初始化时调用,每次路由切换之后调用,路由切换之后指的就是,举个例子说,当前我在A路由组件,我要切换到B路由组件,那么后置路由守卫就是在我点了切换按钮B路由组件呈现到页面中后被调用。

① 执行时间
初始化时执行,每次路由切换后执行
② 使用场景
对于分析、更改页面标题、声明页面等辅助功能以及许多其他事情都很有用。
③ 注意项
不会接受 next函数,也不会改变导航本身
④ 使用方法
可以使用 router.afterEach 注册一个全局后置守卫

const router = new VueRouter({ ... })

//全局后置路由守卫————初始化的时候被调用、每次路由切换之后被调用
router.afterEach( (to,from)=>{
  console.log('后置路由守卫',to,from)
  //修改网页的title
  document.title =  to.meta.title ||'小白学习路由守卫'
})

路由独享的守卫

  • 组件独享守卫是在进入组件时被调用,区别就在于,想对那个路由进行权限控制就直接在其路由配置项中添加守卫,作用域也仅限于该路由

① 执行时间
独享守卫 只在进入路由时触发,不会在 params、query 或 hash 改变时触发。它们只有在 从一个不同的 路由导航时,才会被触发。
② 注意项
独享守卫没有后置,可以全局后置路由守卫搭配使用
③ 使用方法
直接在路由配置上使用 beforeEnter定义独享守卫

你可以在路由配置上直接定义 beforeEnter 守卫:【逻辑判断也在beforeEnter里面写】


const routes = [
  {
    path: '/users/:id',
    component: UserDetails,
    beforeEnter(to,from,next){
        //逻辑判断写在此处
    },
  },
]

这些守卫与全局前置守卫的方法参数是一样的。

  • 全局路由守卫服务的是所有路由组件,而独享路由守卫只服务于被配置的单个路由组件

组件内的守卫

当使用路由规则进入该组件或离开该组件时,就会触发组件内守卫的调用,而组件内守卫的作用于范围也仅限于该组件

  • beforeRouteEnter
  • beforeRouteUpdate (2.2 新增)
  • beforeRouteLeave
const Foo = {
  template: `...`,
  //进入守卫:通过路由规则,进入该组件时被调用  
  beforeRouteEnter(to, from, next) {
    // 在渲染该组件的对应路由被 confirm 前调用
    // 不!能!获取组件实例 `this`
    // 因为当守卫执行前,组件实例还没被创建
  },
  beforeRouteUpdate(to, from, next) {
    // 在当前路由改变,但是该组件被复用时调用
    // 举例来说,对于一个带有动态参数的路径 /foo/:id,在 /foo/1 和 /foo/2 之间跳转的时候,
    // 由于会渲染同样的 Foo 组件,因此组件实例会被复用。而这个钩子就会在这个情况下被调用。
    // 可以访问组件实例 `this`
  },
  //离开守卫:通过路由规则,离开该组件时被调用  
  beforeRouteLeave(to, from, next) {
    // 导航离开该组件的对应路由时调用
    // 可以访问组件实例 `this`
  }
}

beforeRouteEnter 守卫 不能 访问 this,因为守卫在导航确认前被调用,因此即将登场的新组件还没被创建。

不过,你可以通过传一个回调给 next来访问组件实例。在导航被确认的时候执行回调,并且把组件实例作为回调方法的参数。

beforeRouteEnter (to, from, next) {
  next(vm => {
    // 通过 `vm` 访问组件实例
  })
}

注意 beforeRouteEnter 是支持给 next 传递回调的唯一守卫。对于 beforeRouteUpdatebeforeRouteLeave 来说,this 已经可用了,所以不支持传递回调,因为没有必要了。

beforeRouteUpdate (to, from, next) {
  // just use `this`
  this.name = to.params.name
  next()
}

这个离开守卫通常用来禁止用户在还未保存修改前突然离开。该导航可以通过 next(false) 来取消。

beforeRouteLeave (to, from, next) {
  const answer = alert('还未保存,确定要离开吗')//放行
  if (answer) {
    next()//放行
  } else {
    next(false)//取消
  }
}

唯一不同于之前的就是:BeforeRouterLeave(),它并不像全局后置守卫一样在路由组件加载完成之后调用,而是在你切换出这个组件后被调用,也就是离开这个组件后被调用,在开发中,我们也可以使用BeforeRouterLeave() 来完成某些操作,比如当我要切换出该组件事,我希望该组件的操作能暂停,而不是一直运行,只有当我切换回该组件时,又再次运行,这样的操作就可以配合着beforeRouteEnter() 来完成,也可以提高应用的性能。

完整的导航解析流程

  1. 导航被触发。

  2. 在失活的组件里调用 离开守卫beforeRouteLeave

  3. 调用全局前置守卫 beforeEach

  4. 在重用的组件里调用更新守卫 beforeRouteUpdate (2.2+)。

    举例来说,对于一个带有动态参数的路径 /users/:id,在 /users/1/users/2 之间跳转的时候, 由于会渲染同样的 UserDetails 组件,因此组件实例会被复用。而这个钩子就会在这个情况下被调用。

  5. 在路由配置里调用 独享守卫beforeEnter

  6. 解析异步路由组件。

  7. 在被激活的组件里调用 进入守卫beforeRouteEnter

  8. 调用全局解析守卫 beforeResolve (2.5+)。

  9. 导航被确认。

  10. 调用全局后置守卫afterEach

  11. 触发 DOM 更新。

  12. 调用 进入守卫beforeRouteEnter 中传给 next 的回调函数,创建好的组件实例会作为回调函数的参数传入。

路由元信息

通过路由记录的 meta 属性可以定义路由的元信息。使用路由元信息可以在路由中附加自定义的数据,例如:

  1. 每个路由给予独立的标题;
  2. 管理后台的路由,部分页面需要限制一些访问权限;
  3. 通过路由来自动生成侧边栏、面包屑;
  4. 部分路由的生命周期需要做缓存( Keep Alive );
  5. 其他更多业务场景…

我们可以在导航守卫或者是路由对象中访问路由的元信息数据。

const routes = [
  {
    path: '/posts',
    component: PostsLayout,
    children: [
      {
        path: 'new',
        component: PostsNew,
        // 只有经过身份验证的用户才能创建帖子
        meta: { requiresAuth: true, title:'创建帖子'}
      },
      {
        path: ':id',
        component: PostsDetail,
        // 任何人都可以阅读文章
        meta: { requiresAuth: false ,title:'阅读文章'}
      }
    ]
  }
]

后续等vue2所有基础知识学完后,整个学习笔记的代码会上传到github

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值