路由是一个单页应用的核心,大部分前端框架都实现了一个复杂的路由库,包括动态路由,路由钩子,组件生命周期甚至服务器端渲染等复杂的功能。但是对于前端开发者而言,路由组件的核心是URL路径到函数的映射,了解了这个概念,便可以亲自实现一个简单的路由功能。
1.路由的原理
路由(Route)在前端可以理解为URL路径到函数的映射。当访问到一个特定的路径时执行特定的函数。另一个概念Router,用于管理各种Route,也就是匹配路径到函数的过程。
2.实现路由
Web端实现路由有两种技术模式。
- 基于Hash
- 基于History API
Hash路由的路径中会有一个“#”标志,即常说的锚点,前端向后端服务器发送请求时并不会解析Hash部分。路由实现通过监听页面window对象的hashChange事情,调用对应的函数,优点是兼容性好且完全脱离后端,缺点是因为带了Hash标志导致路由不直观。
History API通过监听HTML 5添加的popstate事件,URL格式跟传统的后端路由一致,这也是这种模式最大的优点。缺点是只有新型浏览器支持该特性,且需要后端路由配合,因为当用户访问一个History路由实现的路径时,页面仍会像后端请求,如果后端没有设置相应的路由实现逻辑,将返回404错误。
根据前端路由的概念,实现一个路由需要三个部分:存储路径和对应的回调方法,监听浏览器的相关事件,根据监听结果执行路径对应回调方法。根据这些要求,在开发的路由模块中,设计一个对象通过“Key-Value”模式存放路径和对应方法,再通过window对象监听popstate事件,根据当前的路径从路由对象中选择执行对应的方法,实现的代码如下:
function Router() { this.routes = {}; // 存放路径和对应方法 this.route = function(path, callback) { // 实例化后通过调用来增加新的路由 this.routes[path] = callback; // 通过key-value存放callback } this.refresh = function() { // 通过一个函数调用最终的callback var curUrl = location.hash.slice(1) || ‘/’; // 在Hash模式下获取路径 // var curUrl = location.pathname; // 在History API模式下获取路径 this.routes[curUrl](); // 调用最终的callback } this.init = function() { // 初始化方法 // 监听load事件对应第一次页面加载 window.addEventListener(‘load’, this.refresh.bind(this), false); // Hash模式下监听hashchange事件 window.addEventListener(‘hashchange’, this.refresh.bind(this), false); // History API模式下监听popstate事件 // window.addEventListener(‘popstate’, this.refresh.bind(this), false); } }
在实际开发过程中,需要调用route方法添加路由和对应方法,使用代码如下:
var router = new Router(); // 实例化Router方法 router.init(); // init来监听对应的全局事件 router.route(‘/’, function() { … }); // 用过route方法添加新的路由和对应方法 router.route(‘test’, function() {…});
这样就实现了一个功能简单的单页路由,对于使用了React或者Vue.js这样的复杂单页应用,路由组件还实现了一系列复杂的功能。本节只实现了一个简单的路由模块,其他复杂的功能可以参考React Router或者axios(Vue 2.0推荐路由)的源码。
更多信息关注: