前端路由实现 - hash篇

栏目: 数据库 · 发布时间: 8年前

内容简介:前端路由实现 - hash篇

许多前端框架 angular,vue,react 他们都有各自的路由系统,管理着前端的页面视图切换,如果想了解其原理,最好方法就是手动实现一个。

SPA 的前端路由有2种实现方式:

  • 一种是HTML5推出的 History API
  • 另一种 hash 路由,就是常见的 # 号,这种方式兼容性更好。

需求分析

这里基于ES6 class声明的方式,实现的一个简单的路由类 SPARouter 包含以下功能:

  1. 基本hash路由功能
  2. 异步加载js组件,同步加载组件
  3. 组件传参
  4. 路由钩子函数:beforeEach()、afterEach()

实现步骤

  1. 切换页面:hash路由切换是不会刷新页面的,浏览器有个全局变量 location 下有个属性值叫 hash ,每当 hash 的值改变时,就会触发 hashchange 事件,所以我们可以通过监听 hashchange 事件来切换我们的页面。监听代码如下:

     // 页面初始化时是没有hashchange时间的,但是如果hash值匹配到相应的路由,我们也需要更新页面
     window.addEventListener('load', () => {
       console.log('load')
       this.routeUpdate();
     });
    // 监听hash变化,来切换页面
     window.addEventListener('hashchange',function(){
     	console.log('hashchange')
       this.routeUpdate();
     })
    
  2. 注册路由:初始化全局路由对象的时候,需要先定于路由规则,这样页面才会知道如何根据hash变化来切换界面。

    /* 
     * 注册函数
     * routes变量是要在创建我们的路由类时传入构造函数的参数,
     * 它是一个数组,它的元素就是我们定义的没每个路由对象,
     * path - 路由路径
     * filename - js组件存储路径
     * initFunc - 可缺省,如果未定义filename属性,则可通过定义此函数来初始化该路由视图
     */ 
    var routes = [
        {
            path: '/index',
            filename: 'components/index.js'
        },
        //...
    ]
    
  3. 创建router对象实例, 将路由规则传入。

    var router = new SPARouter(routes)
    
  1. 从页面url中获取hash路由:

    getHashRoute() {
        let hashDetail = window
          .location
          .hash
          .split('?');
        let hashName = hashDetail[0].split('#')[1];
        let params = hashDetail[1]
          ? hashDetail[1].split('&')
          : [];
        let query = {};
        params.map((item) => {
          let temp = item.split('=');
          query[temp[0]] = temp[1];
        });
    
        return {path: hashName, query: query};
    }
    
  1. 匹配到相应的路由规则,更新路由视图
routeUpdate() {
    let currentHash = this
     .utils
     .getHashRoute();
    this.currentRoute.query = currentHash['query']
    this
     .routers
     .map((item) => {
       if (item.path === currentHash.path) {
         this.currentRoute = item;
         this.refresh();
       }
     });
    if (!this.currentRoute.path) {
     location.hash = '/index';
    }
}
  1. 异步加载js:一般单页面应用为了性能优化,都会把各个页面的文件拆分开,按需加载,所以路由里面要加入异步加载js文件的功能。异步加载我们就采用最简单的原生方法,创建script标签,动态引入js。
loadComponent() {
    let self = this;
    if (this.currentRoute.filename) {
        var _body = document.getElementsByTagName('body')[0];
        var scriptEle = document.createElement('script');
        scriptEle.src = self.currentRoute.filename;
        scriptEle.async = true;
        scriptEle.type = 'text/javascript';
        window.SPA_ROUTE_INIT = null;
        scriptEle.onload = ()=> {
          self.afterFunc && self.afterFunc(self.currentRoute);
          self.currentRoute.fn = window.SPA_RESOLVE_INIT;
          self
            .currentRoute
            .fn(self.currentRoute);
        }
        _body.appendChild(scriptEle);
    } else {
        // 未定义
        if (self.currentRoute.initFunc) {
          self
            .currentRoute
            .initFunc(self.currentRoute);
            self.afterFunc && self.afterFunc(self.currentRoute);
        } else {
          console.trace('该路由定义出错,filename 和 initFunc 必须定义一个')
        }
    }
}
  1. 参数传递:在我们动态引入单独模块的js之后,我们可能需要给这个模块传递一些单独的参数。这里借鉴了一下jsonp的处理方式,我们把单独模块的js包装成一个函数,提供一个全局的回调方法,加载完成时候再调用回调函数。

    SPA_RESOLVE_INIT = function($router){
        document
    	.getElementById("content")
    	.innerHTML = `<p style="color:#099fde;">当前异步渲染首页${$router.path}</p>`
        console.log($router);
    }
    
  1. 扩展:我们已经完成了基本功能,我们再进行扩展,实现路由钩子函数 beforeEachafterEach

    beforeEach(callback) {
        if (Object.prototype.toString.call(callback) === '[object Function]') {
            this.beforeFunc = callback;
        } else {
            console.trace('路由切换前钩子函数不正确')
        }
    }
    afterEach(callback) {
        if (Object.prototype.toString.call(callback) === '[object Function]') {
            this.afterFunc = callback;
        } else {
            console.trace('路由切换后钩子函数不正确')
        }
    }
    

这样我们就完成了一个简单的hash路由了,可以将其应用到实际的SPA项目,快乐的玩耍了,不过还是有很多不完备的地方,感兴趣的可以继续完善,使其变得更加健壮。

运行效果图

前端路由实现 - hash篇

下一篇将介绍如何利用HTML5的 History API 来实现 history 模式的路由,尽请期待~。

最后附上,完整的 DEMO

坚持原创技术分享,您的支持将鼓励我继续创作!

前端路由实现 - hash篇 支付宝

前端路由实现 - hash篇 微信


以上所述就是小编给大家介绍的《前端路由实现 - hash篇》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

Open Data Structures

Open Data Structures

Pat Morin / AU Press / 2013-6 / USD 29.66

Offered as an introduction to the field of data structures and algorithms, Open Data Structures covers the implementation and analysis of data structures for sequences (lists), queues, priority queues......一起来看看 《Open Data Structures》 这本书的介绍吧!

HTML 编码/解码
HTML 编码/解码

HTML 编码/解码

UNIX 时间戳转换
UNIX 时间戳转换

UNIX 时间戳转换

RGB HSV 转换
RGB HSV 转换

RGB HSV 互转工具