<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          【W(wǎng)eb技術(shù)】1254- 深度剖析:一文搞懂前端路由原理

          共 4151字,需瀏覽 9分鐘

           ·

          2022-03-08 00:29

          前言

          前端三大框架?Angular、React、Vue?,它們的路由解決方案?angular/router、react-routervue-router?都是基于前端路由原理進(jìn)行封裝實(shí)現(xiàn)的,因此將前端路由原理進(jìn)行了解和掌握是很有必要的,因?yàn)槲覀冊(cè)偈褂玫倪^程中也難免會(huì)遇到一些坑,一旦我們掌握了它的實(shí)現(xiàn)原理,那么就能在開發(fā)中對(duì)路由的使用更加游刃有余。

          一、什么是路由?

          路由的概念起源于服務(wù)端,在以前前后端不分離的時(shí)候,由后端來控制路由,當(dāng)接收到客戶端發(fā)來的?HTTP?請(qǐng)求,就會(huì)根據(jù)所請(qǐng)求的相應(yīng)?URL,來找到相應(yīng)的映射函數(shù),然后執(zhí)行該函數(shù),并將函數(shù)的返回值發(fā)送給客戶端。對(duì)于最簡(jiǎn)單的靜態(tài)資源服務(wù)器,可以認(rèn)為,所有?URL?的映射函數(shù)就是一個(gè)文件讀取操作。對(duì)于動(dòng)態(tài)資源,映射函數(shù)可能是一個(gè)數(shù)據(jù)庫讀取操作,也可能是進(jìn)行一些數(shù)據(jù)的處理等等。然后根據(jù)這些讀取的數(shù)據(jù),在服務(wù)器端就使用相應(yīng)的模板來對(duì)頁面進(jìn)行渲染后,再返回渲染完畢的頁面。它的好處與缺點(diǎn)非常明顯:

          • 好處:安全性好,SEO?好;

          • 缺點(diǎn):加大服務(wù)器的壓力,不利于用戶體驗(yàn),代碼冗合不好維護(hù);

          也正是由于后端路由還存在著自己的不足,前端路由才有了自己的發(fā)展空間。對(duì)于前端路由來說,路由的映射函數(shù)通常是進(jìn)行一些?DOM?的顯示和隱藏操作。這樣,當(dāng)訪問不同的路徑的時(shí)候,會(huì)顯示不同的頁面組件。前端路由主要有以下兩種實(shí)現(xiàn)方案:

          • Hash

          • History

          當(dāng)然,前端路由也存在缺陷:使用瀏覽器的前進(jìn),后退鍵時(shí)會(huì)重新發(fā)送請(qǐng)求,來獲取數(shù)據(jù),沒有合理地利用緩存。但總的來說,現(xiàn)在前端路由已經(jīng)是實(shí)現(xiàn)路由的主要方式了,前端三大框架?AngularReact、Vue?,它們的路由解決方案?angular/router、react-router、vue-router?都是基于前端路由進(jìn)行開發(fā)的,因此將前端路由進(jìn)行了解和 掌握是很有必要的,下面我們分別對(duì)兩種常見的前端路由模式?Hash?和?History?進(jìn)行講解。

          二、前端路由的兩種實(shí)現(xiàn)

          2.1、Hash 模式

          2.1.1、原理

          早期的前端路由的實(shí)現(xiàn)就是基于?location.hash?來實(shí)現(xiàn)的。其實(shí)現(xiàn)原理也很簡(jiǎn)單,location.hash?的值就是?URL?中 # 后面的內(nèi)容。比如下面這個(gè)網(wǎng)站,它的?location.hash?的值為?'#search'

          https://www.word.com#search

          此外,hash?也存在下面幾個(gè)特性:

          • URL?中?hash?值只是客戶端的一種狀態(tài),也就是說當(dāng)向服務(wù)器端發(fā)出請(qǐng)求時(shí),hash?部分不會(huì)被發(fā)送。

          • hash?值的改變,都會(huì)在瀏覽器的訪問歷史中增加一個(gè)記錄。因此我們能通過瀏覽器的回退、前進(jìn)按鈕控制hash?的切換。

          • 我們可以使用?hashchange?事件來監(jiān)聽?hash?的變化。

          我們可以通過兩種方式觸發(fā)?hash?變化,一種是通過?a?標(biāo)簽,并設(shè)置?href?屬性,當(dāng)用戶點(diǎn)擊這個(gè)標(biāo)簽后,URL?就會(huì)發(fā)生改變,也就會(huì)觸發(fā)?hashchange?事件了:

          <a href="#search">searcha>

          還有一種方式就是直接使用?JavaScript來對(duì)?loaction.hash?進(jìn)行賦值,從而改變?URL,觸發(fā)?hashchange?事件:

          location.hash="#search"

          以下實(shí)現(xiàn)我們采用第2種方式來實(shí)現(xiàn)。

          2.1.2、實(shí)現(xiàn)

          我們先定義一個(gè)父類?BaseRouter,用于實(shí)現(xiàn)?Hash?路由和?History?路由的一些共有方法;

          export class BaseRouter {  // list 表示路由表  constructor(list) {    this.list = list;  }  // 頁面渲染函數(shù)  render(state) {    let ele = this.list.find(ele => ele.path === state);    ele = ele ? ele : this.list.find(ele => ele.path === '*');    ELEMENT.innerText = ele.component;  }}

          我們簡(jiǎn)單實(shí)現(xiàn)了?push?壓入功能、go?前進(jìn)/后退功能,相關(guān)代碼的注釋都已經(jīng)標(biāo)上,簡(jiǎn)單易懂,就不在一 一介紹,參見如下:

          export class HashRouter extends BaseRouter {  constructor(list) {    super(list);    this.handler();    // 監(jiān)聽 hashchange 事件    window.addEventListener('hashchange', e => {      this.handler();    });  }  // hash 改變時(shí),重新渲染頁面  handler() {    this.render(this.getState());  }  // 獲取 hash 值  getState() {    const hash = window.location.hash;    return hash ? hash.slice(1) : '/';  }  // push 新的頁面  push(path) {    window.location.hash = path;  }  // 獲取 默認(rèn)頁 url  getUrl(path) {    const href = window.location.href;    const i = href.indexOf('#');    const base = i >= 0 ? href.slice(0, i) : href;    return base +'#'+ path;  }  // 替換頁面  replace(path) {    window.location.replace(this.getUrl(path));  }  // 前進(jìn) or 后退瀏覽歷史  go(n) {    window.history.go(n);  }}

          2.1.3、效果圖

          Hash?模式的路由實(shí)現(xiàn)例子的效果圖如下所示:

          2.2、History 模式

          2.2.1、原理

          前面的?hash?雖然也很不錯(cuò),但使用時(shí)都需要加上 #,并不是很美觀。因此到了?HTML5,又提供了?History API?來實(shí)現(xiàn)?URL?的變化。其中做最主要的?API?有以下兩個(gè):history.pushState()?和?history.repalceState()。這兩個(gè)?API可以在不進(jìn)行刷新的情況下,操作瀏覽器的歷史紀(jì)錄。唯一不同的是,前者是新增一個(gè)歷史記錄,后者是直接替換當(dāng)前的歷史記錄,如下所示:

          window.history.pushState(null, null, path);window.history.replaceState(null, null, path);

          此外,history?存在下面幾個(gè)特性:

          • pushState?和?repalceState?的標(biāo)題(title):一般瀏覽器會(huì)忽略,最好傳入?null?;

          • 我們可以使用?popstate? 事件來監(jiān)聽?url?的變化;

          • history.pushState()?或?history.replaceState()?不會(huì)觸發(fā)?popstate?事件,這時(shí)我們需要手動(dòng)觸發(fā)頁面渲染;

          2.2.2、實(shí)現(xiàn)

          我們同樣簡(jiǎn)單實(shí)現(xiàn)了?push?壓入功能、go?前進(jìn)/后退功能,相關(guān)代碼的注釋都已經(jīng)標(biāo)上,簡(jiǎn)單易懂,就不在一 一介紹,參見如下:

          export class HistoryRouter extends BaseRouter {  constructor(list) {    super(list);    this.handler();    // 監(jiān)聽 popstate 事件    window.addEventListener('popstate', e => {      console.log('觸發(fā) popstate。。。');      this.handler();    });  }  // 渲染頁面  handler() {    this.render(this.getState());  }  // 獲取 url  getState() {    const path = window.location.pathname;    return path ? path : '/';  }  // push 頁面  push(path) {    history.pushState(null, null, path);    this.handler();  }  // replace 頁面  replace(path) {    history.replaceState(null, null, path);    this.handler();  }   // 前進(jìn) or 后退瀏覽歷史  go(n) {    window.history.go(n);  }}

          2.2.3、效果圖

          History?模式的路由實(shí)現(xiàn)例子的效果圖如下所示:

          2.3、兩種路由模式的對(duì)比

          對(duì)比點(diǎn)Hash 模式History 模式
          美觀性帶著 # 字符,較丑簡(jiǎn)潔美觀
          >= ie 8,其它主流瀏覽器>= ie 10,其它主流瀏覽器
          實(shí)用性不需要對(duì)服務(wù)端做改動(dòng)需要服務(wù)端對(duì)路由進(jìn)行相應(yīng)配合設(shè)置


          三、總結(jié)

          本文我們大致介紹了什么是路由、前端路由的源起、以及分析了兩種前端路由:Hash?模式和?History?模式的原理以及簡(jiǎn)單功能實(shí)現(xiàn)。?通過本文對(duì)前端路由原理的掌握,這時(shí)你就可以基于原理基礎(chǔ)去閱讀?vue-router?和?react-router?的源碼實(shí)現(xiàn)了。


          瀏覽 32
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評(píng)論
          圖片
          表情
          推薦
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  久无码久无码AV无码 | 亚洲天堂在线观看视频 | 无码毛片一区二区三区视频免费看 | 日本親子亂子倫XXXX50路 | 水多多成人网站A片在线观看 |