Vue(五)——vue-router(路由守卫)_组件内守卫实现商品价格排序/全局守卫实现鉴权

89 篇文章 7 订阅

路由守卫

当导航发生改变的时候,vue-router 会在多个不同的地方调用指定的函数,也就是与路由有关的生命周期函数,也称为:路由守卫

  • 组件内守卫
  • 路由独享守卫:写在某个路由配置里
  • 全局守卫:写在整个路由对象里

一、组件内守卫

定义在组件内的与路由有关的生命周期函数(守卫)

  • beforeRouteEnter
  • beforeRouteUpdate
  • beforeRouteLeave

1.1 beforeRouteEnter

当路由解析完成,并中指定的组件渲染之前(组件 beforeCreate 之前),不能这里通过 this 访问组件实例,需要通过 next 回调来进行调用 ,回调后的vm即实例对象。

beforeRouteEnter (to, from, next) {
    // 不!能!获取组件实例 `this`
    // 因为当守卫执行前,组件实例还没被创建
  	next(vm => {
      // vm...
    })
}

1.2 beforeRouteUpdate

在当前路由改变,但是该组件被复用时调用

组件被复用时调用(更新):如表单填写后离开页面时询问是否要提交页面等需求

beforeRouteUpdate (to, from, next) {
    // 可以访问组件实例 `this`
},

1.3 beforeRouteLeave

导航离开该组件的对应路由时调用

beforeRouteLeave (to, from, next) {
    // 可以访问组件实例 `this`
}

二、路由守卫参数

2.1 to

即将要进入的目标 路由对象($route)

2.2 from

当前导航正要离开的路由对象($route)

2.3 next

路由确认回调函数,类似 Promise 中的 resolve 函数,一定要确保调用 next 函数,但是后续的导航行为将依赖 next 方法的调用参数

  • next() : 进行管道中的下一个钩子。如果全部钩子执行完了,则导航的状态就是 confirmed (确认的)。next()表示允许继续往下执行
  • next(false) : 中断当前的导航。如果浏览器的 URL 改变了 (可能是用户手动或者浏览器后退按钮),那么 URL 地址会重置到 from 路由对应的地址
  • next('/') 或者 next({ path: '/' }) : 跳转到一个不同的地址。当前的导航被中断,然后进行一个新的导航

示例:组件内守卫实现商品价格排序(解决组件复用性问题:地址栏变化了,页面没有刷新)

//Home.vue
<template>
  <div class="home">
    <h2>商品列表——首页</h2>
    <!-- 使用v-model 绑定排序,并使用 watch进行监听-->
    <select v-model="sort">
      <option value="desc">从高到低</option>
      <option value="asc">从低到高</option>
    </select>
    <ul class="item-list">
      <li class="head">
        <span>名称</span>
        <span>品牌</span>
        <span>价格</span>
        <span>操作</span>
      </li>
      <li v-for="item of items" :key="item.id">
        <span>{{item.name}}</span>
        <span>{{item.vendor}}</span>
        <span>{{item.price|RMB}}</span>
        <span>
          <!-- 注意:用v-bind方式,则属性值里必须是表达式-->
          <!-- <router-link :to="`/item/${item.id}`">查看详情</router-link> -->

          <!-- 以动态路由形式赋值,注意一定要以v-bind形式进行绑定,后台路由需要设置name:'item' -->
          <router-link :to="{name: 'item', params:{id: item.id}}">查看详情</router-link>
        </span>
      </li>
    </ul>
  </div>
</template>

<script>
import axios from "axios";
import RMB from "@/filter/RMB";

export default {
  name: "Home",
  // 注册过滤器
  filters: {
    RMB
  },
  // 注意是在created生命周期中发送请求(组件渲染完成后)
  data() {
    return {
      items: [],
      sort: "desc"
    };
  },
  async created() {
    //  注意this.sort获取位置,是在组件渲染完后立即赋值,否则有可能没有获取到,从而产生异步问题
    this.sort = this.$route.query.sort || this.sort;

    // 注意请求需要使用async await
    await this.getItems();
  },
  // 使用watch监听组件变化,注意watch是对象
  watch: {
    sort() {

      // 监听到sort发生变化后重新发起请求(但是这样不会在url上带上sort=desc不利于分享状态)
      // await this.getItems();

      // 然后通过编程式导航进行跳转(可以拼接字符串,也可以对象形式传参)
      // this.$router.push('/?sort=' + this.sort);

      this.$router.push({
        // 此处name对应路由中Home组件的路由name
        name: "home",
        // 此处为地址栏上地址加上queryString
        query: {
          sort: this.sort
        }
      });

    },
    // 如果使用了路由守卫就不用监听$route
    // 因为vue组件的复用性(vue在地址改变后,发现还是组件还是之前的组件,就不会进行重新创建),光使用queryString+this.$router.push还无法真正刷新页面
    // async $route() {
    //   // 监听到变化时再发一次请求
    //   await this.getItems();
    // }
  },
  methods:{
    async getItems(){
      await axios({
        // 通过axios发起异步代理请求
        url: "/api/items",
        // 此处为发送给后台请求地址加上queryString
        params: {
          sort: this.sort
        }
      }).then(res => {
        // 将获取到的值设置到data中
        this.items = res.data;
      });
    }
  },
  // 组件内守卫,在特定组件中使用
  // 当路由解析完成,并中指定的组件渲染之前
  // next('/') 或者 next({ path: '/' }) : 跳转到一个不同的地址
  beforeRouteEnter(to, from, next){
    console.log("beforeRouteEnter");
    // 此处处理在组件渲染之前,先跳转到其他地址
    // 注意next之前不能调用this获取实例
     console.log(this);//undefined
    // next(_this=>{
    //   console.log(_this);//此处_this即为组件实例
    // });
    next();
  },
  // 组件被复用时调用(更新):如表单填写后离开页面时询问是否要提交页面等需求
  beforeRouteUpdate(to, from, next){
    // 注意不是使用了路由守卫这里就不需要this.$router.push(),这是为了编程的方式来导航(跳转)
    // 此处使用了this.$router.push()方法,阻隔了组件的复用性,所以组件复用时就会调用
    console.log("beforeRouteUpdate");
    // 更新时,只有此处next()确认后才能生效
    // 使用路由守卫发起请求,不再监听$route对象
    this.getItems();
    next();
  },
  // 导航离开该组件时调用
  beforeRouteLeave(to, from, next){
    console.log("beforeRouteLeave");
    next();
  }
};
</script>

<style>
ul {
  margin: 0;
  padding: 0;
}

li {
  list-style: none;
}

.item-list li {
  padding: 10px;
  display: flex;
  justify-content: space-between;
  height: 30px;
  line-height: 30px;
  border-bottom: 1px dotted #333;
}
.item-list li.head {
  font-weight: bold;
}
.item-list li span {
  min-width: 200px;
}
</style>

三、路由独享守卫

可以在路由配置上直接定义 beforeEnter 守卫,相对来说,应用不多

const router = new VueRouter(
  { 
    routes: [ 
      { 
        path: '/foo', 
        component: Foo, 
        beforeEnter: (to, from, next) => { 
          // ... 
      	}
    	} 
    ] 
  }
)

四、全局守卫

全局守卫是注册在 router 对象(new VueRouter({...}))上的

  • beforeEach

  • beforeResolve

  • afterEach

4.1 beforeEach

当一个导航触发时,全局前置守卫按照创建顺序调用

router.beforeEach((to, from, next) => {
  // ...
})

4.2 beforeResolve

在所有组件内守卫和异步路由组件被解析之后被调用

router.beforeResolve((to, from, next) => {
  // ...
})

4.3 afterEach

导航被确认后调用

router.afterEach((to, from) => {
  // ...
})

因为导航已经被确认,所以没有 next

示例, 全局守卫实现鉴权:

//Login.vue
<template>
  <div>
      Login
  </div>
</template>

<script>
export default {
    name: 'Login'
}
</script>

<style>

</style>
//route.js
import Vue from 'vue'
import Router from 'vue-router'
import Home from '@/components/Home.vue'
import About from '@/components/About.vue'
import Item from '@/components/Item.vue'
import Login from '@/components/Login.vue'

Vue.use(Router)

const appRouter = new Router({
    mode: 'history',
    routes: [{
            name: "home",
            path: '/',
            component: Home
        },
        {
            name: "about",
            path: '/about',
            component: About,
            // 利用路由元信息进行鉴权
            meta: {
                requiresAuth: true
            }
        },
        {
            // 页面以动态路由形式赋值时:to='{name: "item", params:{id: item.id}}',需要给路由设置name才能赋值
            name: 'item',

            //  :id配置在route配置时
            path: '/item/:id',
            component: Item,
            // 利用路由元信息进行鉴权
            meta: {
                // requiresAuth: true
            }
        },
        {
            name: "login",
            path: '/Login',
            component: Login
        },
    ]

});

// 全局守卫(处理如鉴权等需求)
// 当一个导航触发时,全局前置守卫按照创建顺序调用
let user = { id: 1 }
appRouter.beforeEach((to, from, next) => {
    // 点击About和Item(查看详情)时,需要进行鉴权
    console.log(to, from);
     if (["about", "item"].includes(to.name) || user.id === 0) {
         next({ name: 'login' });
     }
})

// 在所有组件内守卫和异步路由组件被解析之后被调用
appRouter.beforeResolve((to, from, next) => {
    next();
})

// 导航被确认后调用:因为导航已经被确认,所以没有 next
appRouter.afterEach((to, from) => {

})

export default appRouter;

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Vue-router提供了导航守卫来保护路由的导航。导航守卫可以在跳转或取消导航的过程中进行拦截。导航守卫可以分为全局守卫、路由独享守卫组件守卫全局守卫是注册在router实例上的,可以使用router.beforeEach方法注册一个全局前置守卫。在每次路由切换之前,全局前置守卫会被触发并接收to、from和next三个参数。可以在全局前置守卫中进行一些权限验证或者其他操作,然后通过调用next方法来进行导航。 路由独享守卫是在定义路由的时候通过beforeEnter属性来注册。路由独享守卫只会对特定的路由生效,可以在路由配置中定义一个beforeEnter函数来进行拦截操作。 组件守卫是使用vue-router提供的beforeRouteEnter、beforeRouteUpdate和beforeRouteLeave方法来注册。beforeRouteEnter在进入路由前被调用,而beforeRouteUpdate在当前路由复用时被调用,beforeRouteLeave在离开当前路由时被调用。这些守卫可以在组件内部进行定义,并可以在组件内部进行一些操作,比如获取数据或者进行一些清理工作。 总结起来,vue-router路由守卫提供了全局守卫、路由独享守卫组件守卫来保护路由的导航,可以在不同的阶段进行各种操作,确保路由的安全和灵活性。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *2* *3* [Vue路由守卫(导航守卫)](https://blog.csdn.net/m0_48949881/article/details/122436528)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 100%"] [ .reference_list ]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值