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>

發佈了17 篇原創文章 · 獲贊 0 · 訪問量 2萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章