在學習react router時,看到有關history有如下描述:
react router 是建立在 history 之上的。 簡而言之,乙個 history 知道如何去監聽瀏覽器位址列的變化, 並解析這個 url 轉化為 location 物件, 然後 router 使用它匹配到路由,最後正確地渲染對應的元件。這段描述看的暈暈的,history到底是個什麼東西呢?這得從history api的出身說起。
我們都知道乙個url代表了網路上唯一的乙個資源。這個資源可以是乙個頁面,一張等等。在位址列裡輸入乙個url位址,瀏覽器就會將對應的資源展示出來。當在不同的位址之間跳轉時,我們很自然地想要回退或者前進乙個位址。為了實現這個功能,瀏覽器廠商定義了history
物件。這時的history
物件大致有go()
、forward()
、back()
等方法,用於實現歷史記錄的訪問、跳轉。
使用 history api與瀏覽器歷史記錄進行互動
history
與 url 就這樣和諧的相處了一段時間,直到ajax技術的興起。
瀏覽器有乙個限制:如果你改變了url,甚至是通過指令碼,它就得向伺服器傳送請求,重新整理整個頁面。這很耗時,也耗資源,因為有時候2個頁面長得差不多,僅僅有一小塊地方不同。為了解決這個問題,ajax
技術興起,利用ajax,可以不改變url,只向伺服器請求需要變動的資料,然後在前端通過dom操作實現頁面的區域性更新。
ajax
極大提高了頁面載入速度與使用者體驗。不過它同時帶來了乙個問題:同乙個url位址,可能會展示很多不同的資訊,那麼它作為唯一資源識別符號的這個定義,在這裡被破壞了。
有沒有乙個兩全其美的辦法呢?既可以實現頁面的區域性更新,又能夠改變位址列裡的url?
井號方案
第乙個跳出來解決問題的是url中的#
。#
代表網頁中的乙個位置。它右邊的字元就是頁面中的位置識別符號。例如下面的url:
就代表網頁index.html的print位置。瀏覽器讀取這個url後,會自動將print位置滾動至對應的區域。為網頁位置指定識別符號,有兩個方法。一是使用錨點,比如,二是使用id屬性,比如
#
的威力在於它是用來指導瀏覽器動作的,對伺服器端完全無用。所以,http請求中不包括#
,改變#
不觸發網頁過載。因此,如果我們在使用ajax區域性重新整理頁面時,同時改變url#
後面的識別符號,就實現了區域性重新整理+改變url了。
事實上,早前的twitter、google就是這麼實現的。google甚至為此專門定義了乙個搜尋引擎優化的識別符號#!
。可以參考這篇文章:url的井號
history方案
url畢竟是用於資源分享的,帶個#
總感覺有點彆扭。如果不用#
,有沒有辦法能夠修改url,同時又不向伺服器傳送請求呢?這就輪到history物件再次登場了。在html5規範中,w3c對history物件進行了一波公升級:
html5 history api包括2個方法:history.pushstate()和history.replacestate(),以及1個事件:window.onpopstate。通過指令碼傳送ajax請求到伺服器,獲取伺服器響應資料
根據響應的資料操作dom,更新頁面內容
利用history.pushstate()或replacestate()方法,修改位址列中的url
問題得到解決。
在react router中,將上述2個方案進行了整合,統一到了乙個history庫中。也就是我們看到的hashhistory
和browserhistory
。hashhistory
是上面井號方案的封裝,browserhistory
則是對history方案的封裝。特別需要注意到是,browserhistory需要對伺服器端改造。
為什麼?
/welcome
/detail
如果我們在瀏覽器裡直接輸入主頁面位址,然後通過頁面裡鏈結跳轉到二級頁面,一般是沒有問題的。但是,如果在瀏覽器裡直接輸入/welcome
會發生什麼呢?
瀏覽器會認為這是乙個url請求,向伺服器端請求這個url代表的資源。但我們這是乙個單頁面應用,服務端只有乙個index.html頁面,沒有跟這個位址匹配的資源,頁面就會報錯了。
因此,我們需要稍微改造一下服務端,將所有這樣的請求都指向index.html頁面,由前台處理路由資訊。
#
有話說:
為嘛,長得醜就要被淘汰嗎!
react router在ts中的宣告使用
當我們使用react router進行路由跳轉的時候,我們通常都會傳遞一些引數例如 param,state,query 目前已經被廢棄 但是結合typescript使用時,我們需要宣告元件的props型別,否則的話我們的tslint就會阻止程式的繼續執行,接下來我就介紹一下在react中元件的ts宣...
聊聊javascript中的陣列
定義陣列 1.var 陣列名稱 元素1,元素2,var arr 定義空陣列 var arr1 100,前端 true,undefined 定義陣列同時新增不同型別的元素2.建構函式方式 var 陣列名稱 new array 元素1,元素2,var 陣列名稱 new array length leng...
聊聊golang中的鎖
學習過作業系統的都知道程式有臨界區這個概念,臨界區就是程式片段訪問臨界資源的那部分 臨界區同一時刻只能有乙個執行緒進行訪問,其他執行緒需要訪問的話必須等待資源空閒。那麼一般程式語言都會使用鎖來進行臨界區訪問控制。golang主要有兩種鎖 互斥鎖和讀寫鎖 互斥鎖mutex mutex 用於提供一種加鎖...