關(guān)于前端路由

什么是路由

簡(jiǎn)單來(lái)說(shuō)路由就是用來(lái)跟后端服務(wù)器進(jìn)行交互的一種方式,通過(guò)不同的路徑,來(lái)請(qǐng)求不同的資源(if...else...),給我一個(gè)路徑,我給你返回一個(gè)響應(yīng),請(qǐng)求不同的頁(yè)面是路由的其中一種功能。

前端路由

我們通過(guò)一個(gè)狀態(tài)切換的例子來(lái)理解前端路由,代碼如下:

  // HTML
  <x-tab>
    <ol class="nav">
      <li>tab 1</li>
      <li>tab 2</li>
    </ol>
    <ol class="content">
      <li>content 1</li>
      <li>content 2</li>
    </ol>
  </x-tab>

  // CSS
  x-tab{ display: block; }
  x-tab > .nav > li.active{ background: red; }
  x-tab > .content > li{ display: none; }
  x-tab > .content > li.active{ display: block; }

  // js(引入jquery)
  $('x-tab').on('click', '.nav > li', (e)=>{
    let $li = $(e.currentTarget);
    $li.addClass('active').siblings().removeClass('active');
    let index = $li.index();
    $li.closest('x-tab').find('.content > li').eq(index).addClass('active')
      .siblings().removeClass('active')
  })

這樣實(shí)現(xiàn)了點(diǎn)擊tab-1,出現(xiàn)對(duì)應(yīng)的 content-1 的內(nèi)容,點(diǎn)擊tab-2,出現(xiàn)對(duì)應(yīng)的 content-2 的內(nèi)容的功能。

現(xiàn)在,我們先設(shè)置 tab-1的狀態(tài)為 active,content-1 也為 active。刷新頁(yè)面,我們點(diǎn)擊 tab-2,tab-2 就被激活了。這個(gè)時(shí)候,我們刷新頁(yè)面或者是將此頁(yè)面分享給別人,打開(kāi)頁(yè)面以后又回到了 tab-1,這樣就會(huì)出現(xiàn)同樣的 url 看到的界面卻是不一樣的。那么如何才能使你的界面狀態(tài)是可分享?

1. 使用哈希來(lái)保存當(dāng)前頁(yè)面狀態(tài)信息
通過(guò) index 來(lái)記錄用戶點(diǎn)擊的是第幾個(gè) tab, 使用 hash 來(lái)記錄這個(gè)狀態(tài)。

  // HTML和CSS不變
  // js
  let index = location.hash || '#0' //2
  index = index.substring(1)  //3
  $('x-tab > .nav > li').eq(index).addClass('active').siblings()
    .removeClass('active');
  $('x-tab > .content > li').eq(index).addClass('active').siblings()
    .removeClass('active');    

  $('x-tab').on('click', '.nav > li', (e)=>{
    let $li = $(e.currentTarget);
    $li.addClass('active').siblings().removeClass('active');
    let index = $li.index(); //點(diǎn)的是第幾個(gè)tab
    location.hash = index // 1
    $li.closest('x-tab').find('.content > li').eq(index).addClass('active')
      .siblings().removeClass('active')
  })

通過(guò)三個(gè)步驟:

  1. 設(shè)置 hash
  2. 讀取 hash
  3. 分享 hash

這樣呢我們的界面狀態(tài)就可以通過(guò)錨點(diǎn)來(lái)記錄了,將鏈接復(fù)制到另一個(gè)窗口上打開(kāi)依然是原來(lái)的狀態(tài),此時(shí)就簡(jiǎn)單的實(shí)現(xiàn)了,刷新頁(yè)面當(dāng)前狀態(tài)不改變,同時(shí)當(dāng)前狀態(tài)可分享給別人。

2. 使用 a 標(biāo)簽 和監(jiān)聽(tīng)哈希變更事件
上面的例子中,其實(shí)我們點(diǎn)擊事件保存的就是形如后綴為 #0 和 #1 這樣的 url。有沒(méi)有另外一種可能,既然我們是通過(guò)錨點(diǎn)來(lái)切換 tab 的話,那能不能用 a 標(biāo)簽來(lái)做呢?

這樣我們點(diǎn)擊 tab 的時(shí)候更改變化的是 url,就不去監(jiān)聽(tīng) click 事件了,我們監(jiān)聽(tīng)什么事件呢?是哈希變更事件(hashchange),就是如果 a 標(biāo)簽點(diǎn)擊之后哈希是1,就把第一個(gè)添加上一個(gè)紅色背景。代碼如下:

  // HTML
  <x-tab>
    <ol class="nav">
      <li><a href="#0"> tab 1 </a></li>
      <li><a href="#1"> tab 2 </a></li>
    </ol>
    <ol class="content">
      <li>content 1</li>
      <li>content 2</li>
    </ol>
  </x-tab>

  // js
  selectTab()   
  window.onhashchange = (e)=>{
    selectTab()
  }

  function selectTab(){
    let index = location.hash || '#0'
    index = index.substring(1)
    $('x-tab > .nav > li').eq(index).addClass('active').siblings()
      .removeClass('active');
    $('x-tab > .content > li').eq(index).addClass('active').siblings()
      .removeClass('active');  
  }

這種方法代碼也精簡(jiǎn)了很多,其實(shí)就 3 行代碼,首先選擇下 tab,當(dāng)哈希變化的時(shí)候,再選擇一下 tab 。

但是這個(gè)哈希還有很大的問(wèn)題,就是如果還有一個(gè)回到頂部的鏈接。原本我們已經(jīng)選中了 tab-2 ,但是點(diǎn)擊了回到頂部以后原來(lái)的狀態(tài)被覆蓋了,因此在刷新頁(yè)面或其他窗口打開(kāi)的時(shí)候就沒(méi)有了原來(lái)的狀態(tài)。

3. 使用路徑來(lái)代替哈希
在上面的例子中,如果在 a 標(biāo)簽中使用錨點(diǎn)表示某個(gè)狀態(tài),容易被其他的錨點(diǎn)所覆蓋。那么我們直接使用路徑來(lái)代替哈希,當(dāng)點(diǎn)擊 tab1 就跳轉(zhuǎn)到 <a href="./tab1">,當(dāng)點(diǎn)擊 tab2 就跳轉(zhuǎn)到 <a href="./tab2">。

但是這個(gè)請(qǐng)求不可能成功,因?yàn)楹笈_(tái)根本就沒(méi)有響應(yīng) './tab1'和'./tab2'這個(gè)路徑。當(dāng)點(diǎn)擊 tab1 的時(shí)候它會(huì)跳頁(yè)面,就會(huì)去請(qǐng)求 tab1 這個(gè)頁(yè)面,返回的是 404。

實(shí)際上我們的目的不是跳轉(zhuǎn)頁(yè)面只是想改變 url,沒(méi)關(guān)系,我么可以阻止 a 標(biāo)簽的默認(rèn)事件,不要它跳轉(zhuǎn)(e.preventDefault())。

  // HTML
  <x-tab>
    <ol class="nav">
      <li><a href="./tab1"> tab 1 </a></li>
      <li><a href="./tab2"> tab 2 </a></li>
    </ol>
    <ol class="content">
      <li>content 1</li>
      <li>content 2</li>
    </ol>
  </x-tab>

  // js 
  selectTab()   
  $('x-tab').on('click', '.nav > li > a', (e)=>{
    e.preventDefault();
    let a = e.currentTarget;
    let path = a.getAttribute('href');
    window.history.pushState({], xxx, path);
    selectTab();
  })

  function selectTab(){
    let index = location.pathname.substring(1) || 'tab1';
    index = index.substring(3);
    if(index === 1){
      $('x-tab > .nav > li').eq(0).addClass('active').siblings()
        .removeClass('active');
      $('x-tab > .content > li').eq(0).addClass('active').siblings()
        .removeClass('active');  
    }else if(index === 2){
      $('x-tab > .nav > li').eq(1).addClass('active').siblings()
        .removeClass('active');
      $('x-tab > .content > li').eq(1).addClass('active').siblings()
        .removeClass('active'); 
    }
  }

這樣我們點(diǎn)擊 tab1 或者 tab2 的時(shí)候,就只是改了 url,沒(méi)有跳轉(zhuǎn)頁(yè)面這就叫做巧用 History API無(wú)刷新更改地址欄。

現(xiàn)在的問(wèn)題是此時(shí)的頁(yè)面狀態(tài)是不可分享的,返回 404,后臺(tái)沒(méi)有這個(gè)路徑的路由信息。因?yàn)樗械?url 都是先給服務(wù)器過(guò)一遍,然后再給 js 的。

這個(gè)時(shí)候我們可以自己寫(xiě)一個(gè)后端路由來(lái)模擬實(shí)現(xiàn)刷新頁(yè)面后不跳轉(zhuǎn)頁(yè)面,當(dāng)路徑為 / 或者/tab1 或者 /tab2 的時(shí)候都是返回同一個(gè)頁(yè)面。

  if(path === '/' || path === '/tab1' || path === '/tab2'){
    response.statusCode = 200
    response.setHeader('Content-Type', 'text/html;charset=utf-8')
    let string = fs.readFileSync('./index.html','utf8')
    response.write(string)
    response.end()
  }else{
    response.statusCode = 404
    response.setHeader('Content-Type', 'text/html;charset=utf-8')
    response.write('嗚嗚嗚')
    response.end()
  }

這樣就不會(huì)去通知服務(wù)器,js 做的假的頁(yè)面跳轉(zhuǎn),同時(shí)把頁(yè)面更新到對(duì)應(yīng)的狀態(tài)。

現(xiàn)在我們應(yīng)該可以知道了

1. 路由就是給我一個(gè)路徑,我給你返回一個(gè)響應(yīng)

2. 前端路由就是前端頁(yè)面做這個(gè)事情,前端做路由

3. 后端路由呢就是后端做路由

以上的前端路由,也就是 Vue-Router 中 <router-link></router-link>的實(shí)現(xiàn)原理。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 1、通過(guò)CocoaPods安裝項(xiàng)目名稱(chēng)項(xiàng)目信息 AFNetworking網(wǎng)絡(luò)請(qǐng)求組件 FMDB本地?cái)?shù)據(jù)庫(kù)組件 SD...
    陽(yáng)明AI閱讀 16,185評(píng)論 3 119
  • ¥開(kāi)啟¥ 【iAPP實(shí)現(xiàn)進(jìn)入界面執(zhí)行逐一顯】 〖2017-08-25 15:22:14〗 《//首先開(kāi)一個(gè)線程,因...
    小菜c閱讀 7,311評(píng)論 0 17
  • 用到的組件 1、通過(guò)CocoaPods安裝 2、第三方類(lèi)庫(kù)安裝 3、第三方服務(wù) 友盟社會(huì)化分享組件 友盟用戶反饋 ...
    SunnyLeong閱讀 15,158評(píng)論 1 180
  • 我還想再寫(xiě)寫(xiě)關(guān)于緣分的事兒。 昨天傍晚,幾個(gè)堂哥來(lái)看望我的母親,吃飯的時(shí)候,在某系統(tǒng)工作的四哥突然問(wèn)我:“汪**有...
    異次元小辣椒閱讀 328評(píng)論 0 1
  • 前日浙江貓友群里一個(gè)老鄉(xiāng)告訴我有一個(gè)騰訊投資的社交公司要出來(lái)ICO,叫我?guī)退匆幌掳灼?shū)她發(fā)了一個(gè)鏈接給我...
    mindofmic閱讀 1,958評(píng)論 0 0

友情鏈接更多精彩內(nèi)容