一,前言
上篇,介绍创建路由映射表,主要包含以下内容:
本篇,继续介绍两种路由模式的设计;
二,承上启下
1,前文回顾
2,本篇介绍
有了路由配置的映射关系之后,还需要实现根据不同路径跳转并显示对应的组件;本篇,主要介绍两种路由模式的设计及初始化操作;
三,路由跳转的实现
1,路由模式的处理
根据路由选项中所配置的不同路由模式,需要进行不同的处理;
路由模式共有三种,主要介绍 Hash 和 History 两种模式:
 // index.js
import HashHistory from './history/hash';import BrowserHistory from './history/history';
class VueRouter {    constructor(options) {        // 路由配置的扁平化处理        this.matcher = createMatcher(options.routes || []);        // 根据不同的路由模式,生成对应的处理实例        options.mode = options.mode || 'hash'; // 默认hash模式        switch (options.mode) {            case 'hash':                this.history = new HashHistory(this);                break;            case 'history':                this.history = new BrowserHistory(this);                break;        }    }    // 路由初始化方法,供 install 安装时调用    init(app) {}}VueRouter.install = install;export default VueRouter;
   复制代码
 
路由切换时,需要通过 matcher 进行规则匹配,所以在创建两种理由模式的类时,需要传入 this,即当前路由实例;
2,创建两种路由模式类:HashHistory 和 BrowserHistory
创建两种路由模式对应的类:HashHistory 和 BrowserHistory,他们均继承自路由的公共逻辑处理 History 类;
History 类:HashHistory 和 BrowserHistory 的父类,包含两种路由模式的公共逻辑处理:
 // history/base.jsclass History {  constructor(router) {    this.router = router;  // 存储子类传入的 router 实例  }}
export { History }
   复制代码
 
HashHistory 类:继承自 History 类,对应 Hash 模式下方法的实现:
 // history/hash.jsimport { History } from "./base";
class HashHistory extends History{  constructor(router) {    super(router);    // 调用父类构造方法,并将 router 实例传给父类    this.router = router;  // 存储 router 实例,共内部使用  }}
export default HashHistory
   复制代码
 
BrowserHistory 类:继承自 History 类,对应 History 模式下方法的实现:
 // ---------------------------- // // history/hash.jsimport { History } from "./base";
class BrowserHistory extends History{  constructor(router) {    super(router);    // 调用父类构造方法,并将 router 实例传给父类    this.router = router;  // 存储 router 实例,共内部使用  }}
export default BrowserHistory
   复制代码
 3,Hash 模式的路径处理
Hash 模式下,路径后会默认携带'/'符号,HashHistory 初始化时进行处理;
 import { History } from "./base";
function ensureSlash() {  // location.hash 存在兼容性问题,可根据完整 URL 判断是否包含'/'  if (window.location.hash) {    return;  }  window.location.hash = '/'; // 如果当前路径没有hash,默认为 /}
class HashHistory extends History {  constructor(router) {    super(router);    this.router = router;    // Hash 模式下,对URL路径进行处理,确保包含'/'    ensureSlash();  }}export default HashHistory
   复制代码
 4,父类和子类的设计
- 无论是哪一种路由模式 HashHistory 或 BrowserHistory 都需要通过当前的路径进行路由匹配和跳转 
- 路径获取:Hash 模式获取当前路径 hash 值,history 模式获取当前路径 path 值; 
- 路由监听:Hash 模式监听 hashchange 事件,history 模式监听 popState 事件; 
父类和子类的方法设计:
- base.js: 
- transitionTo 根据路由进行匹配跳转; 
- hash.js: 
- getCurrentLocation:获取当前路径 hash 值; 
- setupListener:监听 hashchange 事件 
- history.js: 
- getCurrentLocation:获取当前路径 path 值; 
- setupListener:监听 popState 事件 
5, 父类和子类方法的实现
父类 History:
 // base.js
class History {    constructor(router) {        this.router = router;    }    // 根据路径进行路由匹配,并添加路径改变的监听器    transitionTo(location, onComplete) {      onComplete && onComplete();    }}
export { History }
   复制代码
 
Hash 模式的子类 HashHistory:
 import { History } from "./base";
class HashHistory extends History{    constructor(router){        super(router);        this.router = router;        ensureSlash();    }    getCurrentLocation(){        // 获取路径的 hash 值        return getHash();    }    setupListener(){        // 当 hash 值变化时,获取新的 hash 值,并进行匹配跳转        window.addEventListener('hashchange',()=>{            this.transitionTo(getHash());        })    }}
export default BrowserHistory
   复制代码
 
History 模式的子类 HashHistory:
 class BrowserHistory extends History{    setupListener(){        // 当路径变化时,拿到新的 hash 值,并进行匹配跳转        window.addEventListener('popState',()=>{            this.transitionTo(getHash());        })    }}
export default BrowserHistory
   复制代码
 6,路由初始化 init 方法
 // index.js
class VueRouter {    constructor(options) {        this.matcher = createMatcher(options.routes || []);        options.mode = options.mode || 'hash';        switch (options.mode) {            case 'hash':                this.history = new HashHistory(this);                break;            case 'history':                this.history = new BrowserHistory(this);                break;        }    }    // 监听 hash 值变化,跳转到对应的路径中    init(app) {        // 当前的history实例:可能是HashHistory,也可能是BrowserHistory;        const history = this.history;        // 设置监听器:内部调用的是不同子类中的实现        const setUpListener = () => {            history.setupListener();        }        // 初始化时,获取当前hash值进行跳转, 并设置监听器        history.transitionTo(            history.getCurrentLocation(),            setUpListener        )    }}VueRouter.install = install;
export default VueRouter;
   复制代码
 
四,结尾
本篇,介绍了两种路由模式的设计及初始化操作,主要涉及以下几个点:
- 创建两种路由模式类; 
- 父类和子类继承方法的设计; 
- 路由初始化 init 处理逻辑; 
下一篇,路由匹配的实现;
评论