一,前言
上篇,介绍创建路由映射表,主要包含以下内容:
本篇,继续介绍两种路由模式的设计;
二,承上启下
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 处理逻辑;
下一篇,路由匹配的实现;
评论