history辅助下的SPA路由实现

      上篇文章简单介绍了html5的history api,这篇将就进入实战环节。看看在history api的辅助下,目前流行的前端SPA框架路由是怎么实现的。

1.什么是SPA

        首先,什么事spa呢?一句话概括:spa就是单页面应用,即:single page application。通过看源码就可以发现,整个网站就只有一个html文件。

        那么,spa有什么优势呢?为什么前端要采用这种技术选型呢?小编总结了下,觉得有点有一下几点:

        a.减小服务器压力。 如果不用SPA,那么我们每次切换页面的时候,就会向服务器发送一个请求,服务器返回一个html文件;但是如果使用了SPA,在切换时,不需要请求服务器,只要通过本地的js来切换即可。并且服务器端就不需要配置路由,完全做到了前后端分离,这对于分工合作的意义可想而知。

        b.增强用户体验,增加app的使用流畅性。 做过spa的同学都知道,使用spa之后,页面在切换的时候非常流畅,完全没有那种不断刷新的感觉,而是非常快的就有了响应,因为js运行速度很快,所以js在做本地路由的时候,就会非常快。

        然则,牛逼的spa就没有缺点了吗?答案是有的。

        a.SEO问题没有html抓不到什么。。。 
        b.刚开始的时候加载可能慢很多 
        c.用户操作需要写逻辑,前进、后退等; 

        d.页面复杂度提高很多,复杂逻辑难度成倍

        a,b两点可以通过服务端渲染克服。目前流行的前端框架也已经能很好的支持服务端渲染。d却要根据具体业务需求合理的进行页面分割、组件划分。至于c,咱们就结合昨天所讲的history api看看具体如何解决。

2.SPA路由实现有哪些

        目前来说,无论是vue,还是react,spa的路由实现方式无非就是以下两者:

            1.hash方式。 使用location.hash和hashchange事件实现路由。  

            2.history api。使用html5的history api实现,主要就是popState事件等。

        hash用的还是比较多的,但是这种方式的url会比较丑陋,会出现 #; 而history api就可以很好的解决这个问题,但是需要后端配置,并且由于是html5中的api,所以兼容性还不是很好,用的时候需要确定你的用户在做决定。

2.1 HashRouter

        具体实现代码如下:

function HashRouter() {
  this.routes = {};
  this.currentUrl = '';
};

HashRouter.prototype.init = function() {
  window.addEventListener( 'load', this.refresh.bind( this ), false );
  window.addEventListener( 'hashchange', this.refresh.bind( this ), false );
};

HashRouter.prototype.refresh = function () {
  this.currentUrl = location.hash.slice( 1 ) || '/';
  this.routes[ this.currentUrl ]();
};

HashRouter.prototype.route = function( path, callback ) {
  this.routes[ path ] = callback || function(){};
};

1.首先定义一个HashRouter构造函数,currentUrl存放当前地址,routes存放历史地址及其各自对应的回调函数。

2.route方法用于向hashRouter对象注册路由地址和回调函数

3.refresh方法会在路由切换时执行刷新页面

4.在路由注册完成后会执行init方法,以监听地址栏hash值的变化

2.2 BrowserRouter

        上面使用的hash方法实现路由固然不错,但是也是存在一定的问题的,就是太丑~ 如果在微信中使用,看不到url倒也无所谓,但是如果在一般的浏览器中使用就会遇到问题了。所以这里使用 history api。具体代码如下:

<script type="text/javascript">
  function MyBrowserRouter() {
    this.currentRoute = '';
    this.routes = {};
    this.init();
  }

  MyBrowserRouter.prototype.route = function( path, callback ) {
    this.routes[ path ] = function( type ) {
      if ( type === 1 ) {
        history.pushState( { path }, path, path );
      } else if ( type === 2 ) {
        history.replaceState( { path }, path, path );
      }
      callback();
    }
  };

  MyBrowserRouter.prototype.refresh = function( path, type ) {
    this.routes[ path ]( type );
  };

  MyBrowserRouter.prototype.init = function() {
    let links = document.querySelectorAll( '.history-link' );

    window.addEventListener( 'load', () => {
      this.currentRoute = location.href.slice( location.href.indexOf( '/', 8 ) );
      this.refresh( this.currentRoute, 2 );
    } );

    window.addEventListener( 'popstate', () => {
      this.currentRoute = history.state.path;
      this.refresh( this.currentRoute, 2 );
    }, false );

    for ( let i = 0; i < links.length; i++ ) {
      links[ i ].onclick = ( e ) => {
        e.preventDefault();
        this.currentRoute = e.target.getAttribute( 'href' );
        this.refresh( this.currentRoute, 2 );
      }
    }
  };
</script>

猜你喜欢

转载自blog.csdn.net/songshuzhong/article/details/80074486