Vue生态及实践 - Vue Router(2)

news2024/11/25 8:11:31

目录

导航守卫

解析流程

代码演示

router.js

pages/Foo.vue

router/router.js

router/history/base.js

router/util/async.js 

router/components/RouterView.vue


接上一篇文章~,代码部分会有部分重叠,想看完整版的代码,看这篇文章的~

导航守卫

当一个路由——检查是否有权限——>另一个路由

vue-router导航守卫有三类:

  1. 全局守卫:beforeEach、beforeResolve、afterEach
  2. 路由独享守卫:beforeEnter
  3. 组件内守卫:beforeRouteEnter、beforeRouteUpdate、beforeRouteLeave

解析流程

 

深颜色:组件上的路由守卫

浅颜色:路由表上路由信息的导航守卫

book————>user;跳转的路由过程中的钩子触发顺序:

  1. beforeRouteLeave(做一些跟销毁相关的处理)
  2. router.beforeEach(触发全局守卫)
  3. beforeRouteUpdate(可重用组件【橙色的'/'】是保持不变的,会触发这个钩子)
  4. beforeEnter(目标路由独享守卫,就是路由表中user的路由守卫)
  5. beforRouteEnter(user路由对应的组件)
  6. router.beforeResolve(全局守卫)
  7. router.afterEach 导航结束触发(它不具备守卫功能,它是个马后炮,这里可以做一些打点,日志处理相关工作,此时跳转路由已经结束)

初始化进入组件时候:守卫顺序是:2、4、5、6、7

代码演示

router.js

// router.js // 路由使用
import Vue from "vue";
// import Router from "vue-router";
import Router from "./router/router";
import Foo from "./pages/Foo";
import Bar from "./pages/Bar";
Vue.use(Router);
const router = new Router({
  routes: [
    {
      path: "/foo",
      component: Foo,
      beforeEnter(to, from, next) {// 单个路由上的守卫
        console.log("/foo::beforeEnter", to, from);
        next();
      }
    },
    { path: "/bar", component: Bar }
  ]
});
// 全局路由守卫
// to 【要前往的路由】
// from 【来自的路由】
// next 【代表是否可以走入下一个路由】
router.beforeEach((to, from, next) => { // 解析前
  console.log("router.beforeEach", to, from);
  next()
  // next(false); 未通过 全局路由守卫
});
router.beforeResolve((to, from, next) => { // 解析完
  console.log("router.beforeResolve", to, from);
  next();
});
router.afterEach((to, from) => { // 解析后,没有守卫功能,只是一个后置的钩子函数
  console.log("router.afterEach", to, from);
});
export default router;

pages/Foo.vue

// pages/Foo.vue 页面组件
<template>
  <div>Foo</div>
</template>
<script>
export default {
    // 组件上的路由守卫钩子函数
  beforeRouteEnter(to, from, next) {
    console.log("foo::beforeRouteEnter", to, from);
    next();
  },
  beforeRouteUpdate(to, from, next) {
    console.log("foo::beforeRouteUpdate", to, from);
    next();
  },
  beforeRouteLeave(to, from, next) {
    console.log("foo::beforeRouteLeave", to, from);
    next();
  },
};
</script>

router/router.js

// router/router.js
// 路由表参数构建
import Vue from 'vue'
import RouterView from './components/RouterView'
import RouterLink from './components/RouterLink'
//注册RouterView组件
Vue.component("RouterView", RouterView)
Vue.component("RouterLink", RouterLink)
class RouterTable {
    constructor( routes ) {
      this._pathMap = new Map()  
      this.init(routes)
    }
    // 初始化函数
    init(routes) {
        const addRoute = (route) => {
            this._pathMap.set(route.path,route)
            if(route.children) {
                // 遍历
                route.children.forEach(cRoute => addRoute(cRoute) );          
            }        
        }
        routes.forEach(route => addRoute(route) );   
    }
    // 找一下path是否存在
    match(path) {
        let find;
        // 获取所有的路径this._pathMap.keys()
        for(const key of this._pathMap.keys()) {
            if(path === key) {
                find = key;
                break;            
            }        
        }
        return this._pathMap.get(find)
    }
}
import Html5Mode from './history/html5';

// 抽取出一个公共函数,此函数是全局守卫的函数,全局钩子函数的注册收集
function registerHook(list, fn) {// list:对应钩子函数的列表,钩子函数
   list.push(fn);   
   return () { // 返回的函数,可以帮我们销毁收集的钩子函数
       const i = list.indexOf(fn); // 获取fn的索引index
       if(i > -1) lists.splice(i, 1); // 删除钩子函数    
   } 
}

// 创建一个构造路由的类
export default class Router {
    constructor({ routes = [] }) {// 构造函数
      this.routerTable = new RouterTable(routes);   // 路由表
      this.history = new Html5Mode(this); // 注入了当前Router实例,路由里可以拿Router
      // 全局守卫——钩子函数需要收集起来
      this.beforeHooks = [];
      this.resolveHooks = [];
      this.afterHooks = [];
    }
    init(app) { // vue单页应用
        const {history} = this;// 解构出history
        history.listen(route => {
            //_route是响应式的
             app._route = route;       
        })
        // 第一次渲染
        history.transitionTo(history.getCurrentLocation());           
    }
    push(to) {
        this.history.push();    
    }
    // 全局守卫——钩子,接收了一个可执行函数参数
    beforeEach(fn) {
       return registerHook(this.beforeHooks, fn) 
    }
    beforeResolve(fn) {        
       return registerHook(this.resolveHooks, fn) 
    }
    afterEach(fn) {
       return registerHook(this.afterHooks, fn)     
    }
}

Router.install = function() {
    Vue.mixin({
        beforeCreate() {
            if(this.$options.router !== undefined) {// 存在router
               this._routerRoot = this;// this指Vue实例
               this._router = this.$options.router;
               this._router.init(this);
               // this._route的路由信息,响应式的,初始值
               Vue.util.defineReactive(this, "_route", this._route.history.current);                                             
            }        
        }    
    })
}

router/history/base.js

// /router/history/base.js
import { runQueue } from "../util/async"
// 监听器【两种Mode都包含的监听器】
export default class BaseHistory {
    constructor(router) {// 依赖反转把routeTable注入进来
    	 this.router = router;
        this.routeTable = router.routeTable;    
    }
    // 注册监听cb函数
    listen(cb) {
         this.cb = cb;   
    }
    // 跳转函数
    transitionTo(target) {
        // 路由匹配
        const route = this.routerTable.match(target);
        // 如果我们的路由配置上找到了这个地址
        // 路由守卫
        // 是否跳转
        this.confirmTransition(route, () => {
           // 通过路由守卫
        	this.updateRoute(route);     
        })
        
    }
    // 是否可以跳转(路由守卫)
    confirmTransition(route, onComplete, onAbort) { // onAbort中断函数
    	if(route == this.current) {// 如果是当前路由,那就不用跳转了
     		return;              
     	}
      	// 守卫队列,顺序执行
     	const queue = [
          ...this.router.beforeHooks,// ...数组展开语法
          route.beforeEnter,
          route.component.beforeRouteEnter.bind(route.instance),// 把这个实例当this上下文传过去
          ...this.router.resolveHooks,
      ];
      	const iterator = (hook, next) => {// hook 守卫
           hook(route, this.current, (to)=>{
               if(to === false) {
                   onAbort && onAbort(to);               
               } else {
                 next(to);   
               }
                     
           })     
      	}
    	runQueue(queue, iterator, () => onComplete())
    }
    // 通过路由守卫后执行此函数
    updateRoute(route) {
        const from = this.current;
        this.current = route;
        // 钩子函数cb,触发RouterView模板刷新
        this.cb(this.current)
        // afterEach // 只是个钩子函数,没有守卫功能
        this.router.afterHooks.forEach(hook => {
            hook && hook(route, from)        
        })
    }
}

router/util/async.js 

// router/util/async.js
// 暴漏出一个执行队列的方法
// queue:队列
// iter:迭代器,对队列中的每一项进行对应操作的回调函数
// end: end函数,在队列执行完毕后执行
export function runQueue(queue, iter, end){
    const step = (index) => {
         if(index >= queue.length) {
             end();
         } else {
             if(queue[index]){
                 iter(queue[index], ()=>{
                     step(index + 1);                    
                 })             
             } else {
                 step(index + 1);             
             }        
         }  
    }
    step(0);
}

router/components/RouterView.vue

// router/components/RouterView.vue
// RouterView组件-渲染页面组件
<script> 
export default {
    name: 'RouterView',
    render() {
        const route = this._routerRoot._route;
        if(!route) {
          return 404;          
        }
        const {component} = route;
        const hook = {
            init(vnode) {
                route.instance = vnode.componentInstance;    
                console.log('vnode', vnode)  
                // Vue组件对应的实例
                console.log('instance', vnode.componentInstance)       
            }        
        }
        return <component hook={hook} />;
    }
}
</script>

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/718752.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

END-TO-END OPTIMIZED IMAGE COMPRESSION论文阅读

END-TO-END OPTIMIZED IMAGE COMPRESSION 文章目录 END-TO-END OPTIMIZED IMAGE COMPRESSION单词重要不重要 摘要&#xff1a; 单词 重要 image compression 图像压缩 quantizer 量化器 rate–distortion performance率失真性能 不重要 a variant of 什么什么的一个变体 …

大数据之flink容错机制

大数据之flink容错机制https://blog.51cto.com/dashujutongmeng/5241407

Spring Batch 批处理框架

一、SpringBatch 介绍 Spring Batch 是一个轻量级、全面的批处理框架&#xff0c;旨在支持开发对企业系统的日常操作至关重要的健壮的批处理应用程序。Spring Batch 建立在人们期望的 Spring Framework 特性&#xff08;生产力、基于 POJO 的开发方法和一般易用性&#xff09;…

从零开始 Spring Boot 60:一个实体映射到多个表

从零开始 Spring Boot 60&#xff1a;一个实体映射到多个表 图源&#xff1a;简书 (jianshu.com) 在之前的文章中我们讨论了 JPA 中的一对一关系&#xff0c;实际上存在一种特殊的一对一关系&#xff0c;即将一个实体映射到多张表&#xff0c;本文会讨论这种关系。 我之前提过…

elementui实现表格自定义排序

需求说明&#xff1a; 1、第一行不参与排序 2、实现带%排序 3、实现null值排序 4、实现值相等不排序 5、实现含有占位符‘–‘排序放到最后 效果图如下&#xff1a; <template> <div><template><el-table border :data"previewTableData" style…

ROS学习之从yaml文件中读取多传感器坐标系之间的静态TF关系并发布Topic

文章目录 0 引言1 工作空间创建并初始化2 创建ROS程序包3 创建yaml读取函数3.1 yaml文件3.2 读取函数 4 创建静态TF关系的发布主函数5 创建launch文件6 编辑CMakeLists.txt7 编译运行7.1 编译7.2 运行 0 引言 机器人中经常使用多种传感器来做定位和建图&#xff0c;而多个传感…

找出一个List中每个元素出现的次数

文章目录 一、需求&#xff1a;找出一个list中&#xff0c;每个元素出现的次数1. 普通实现&#xff08;hashmap&#xff09;&#xff1a;1.1 代码实现&#xff1a;1.2运行结果&#xff1a;1.3 案例分析&#xff1a; 2. 普通实现&#xff08;HashSet#Collections.frequency&…

Flask学习笔记(2)应用部署

本文将介绍如何部署Flask应用。   部署Flask应用&#xff0c;主要是要运用多线程与多进程&#xff0c;提高接口的并发能力。我们以下面的Python代码&#xff08;server.py&#xff09;为例进行演示&#xff1a; # -*- coding: utf-8 -*- import time import datetime from f…

04-HAL库UART配置及协议解析设计

本节内容介绍 1、HAL库UART 在cubemx中的配置及注意事项;2、HAL库UART详解与结构介绍;3、实现简单地UART数据收发&#xff1b; 源码地址&#xff1a; HAL库UART在cubemx中的配置 串口原理图 串口1咱们已经用作rtt的print使用了&#xff0c;所以使用另外一组串口来进行串口…

android studio 4.0以上隐藏调用方法参数名提示

引入&#xff1a; android studio在编辑代码的时候&#xff0c;调用函数时会接口处会自动提示参数名&#xff0c;方便代码书写时对传参命名的规范性。 可以如果代码是魂效过的&#xff0c;那会适得其反&#xff0c;l,l1,l2,i,i1,i2这样的参数名提醒反而会混淆视听。 这时候可…

图书馆机器人的应用,科技助力新趋势

随着科技的发展和智能化时代的到来&#xff0c;图书馆越来越多地引入了机器人作为服务和管理的工具。图书馆机器人可以轻松地完成多种任务&#xff0c;包括为用户提供导航服务、管理借还书、整理图书、清扫图书馆等。 首先&#xff0c;图书馆机器人可以为用户提供导航服务。在庞…

讲讲仿真软件的文件导入

仿真软件识别导入的设计文档是有区别的&#xff0c;实际的使用经历&#xff0c;ADS只是用于搭建Channel通道仿真&#xff0c;那本文以Cadence的Sigrity和Ansys的SIwave为例&#xff0c;讲讲仿真软件的文件导入。 先以Sigrity为例&#xff0c;打开软件&#xff0c;File 菜单Open…

记一次 JVM 参数调整导致 ShardingSphere-Proxy 性能下降的问题排查过程

问题现象 在性能测试中&#xff0c;分别对两个版本差异间隔一天的 ShardingSphere-Proxy 做性能测试&#xff0c;发现版本更新的 Proxy 比旧的 Proxy 在 TPC-C 场景下峰值 tpmC 下降了 7% 左右。 排查过程 在性能测试期间&#xff0c;使用 async-profiler 分别对两个进程进行…

根据aop实现自定义缓存注解

根据aop实现自定义缓存注解 自定义注解 import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; import java.util.concurrent.TimeUnit;/*** author: yanche…

ESP32通过Arduino导出编译bin文件并进行量产烧录

ESP32通过Arduino导出编译bin文件并进行量产烧录 文章目录 ESP32通过Arduino导出编译bin文件并进行量产烧录Arduino导出编译的bin文件方法一&#xff1a;通过Arduino IDE提供的工具导出编译文件方法二&#xff1a;到编译生成的临时文件目录进行查找 弄清楚Arduino的编译烧录过程…

Unity3D:工具栏

推荐&#xff1a;将 NSDT场景编辑器 加入你的3D工具链 3D工具集&#xff1a; NSDT简石数字孪生 工具栏 在 Unity Editor 顶部可以看到工具栏。 工具栏不是窗口&#xff0c;是 Unity 界面中唯一无法重新排列的部分。 有关场景视图中的其他工具&#xff0c;请参阅叠加。 工具栏…

记录一次使用thinkphp5分页器获取数据

// 输出当前页 $nowPage $data->currentPage(); // 输出总条数 $total $data->total(); // 输出当前页条数 $listRows $data->listRows();db(tablename)->where("id > 0")->paginate(10,true,[page>4]); //每页显示10条记录&#xff0c;且打…

C#(五十一)之特性

特性是用于为程序元素添加额外信息的一种机制。比如记录文件修改时间、提示某方法已经过期等。方法、变量、属性、类、接口、结构体以及程序及都是程序元素 Obsolete第二个参数设置为true,调用此方法会产生警告并引起编译器报错 百度了一下C#还有其他的特性以及自定义特性&am…

基于ssm实现图书商城(spring+springmvc+mybatis)

一、项目功能 前台 图书基本展示,包括推荐图书展示和类图书类型展示.推荐图书包括条幅推荐,热销推荐和新品推荐.按照图书类型展示商品.图书详细信息展示.图书加入购物车.修改购物车内图书信息,例如数量等.用户登录.用户注册.修改个人信息,包括密码和收获信息.购物车付款.用户…

前置声明、源文件include、编译链接顺序问题

TestB.h (前置声明&#xff0c;无需在源文件include)重点&#xff1a; 1.前置声明用在指针变量使用&#xff0c;无需在头文件或源文件include 2.继承或者普通变量在头文件使用的时候(除非所有的编译顺序都正确&#xff0c;才能在源文件include)&#xff0c;最好不要在源文件i…