成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專欄INFORMATION COLUMN

從路由原理出發(fā),深入閱讀理解react-router 4.0的源碼

Miyang / 832人閱讀

摘要:通過前端路由可以實(shí)現(xiàn)單頁應(yīng)用本文首先從前端路由的原理出發(fā),詳細(xì)介紹了前端路由原理的變遷。接著從的源碼出發(fā),深入理解是如何實(shí)現(xiàn)前端路由的。執(zhí)行上述的賦值后,頁面的發(fā)生改變。

??react-router等前端路由的原理大致相同,可以實(shí)現(xiàn)無刷新的條件下切換顯示不同的頁面。路由的本質(zhì)就是頁面的URL發(fā)生改變時(shí),頁面的顯示結(jié)果可以根據(jù)URL的變化而變化,但是頁面不會(huì)刷新。通過前端路由可以實(shí)現(xiàn)單頁(SPA)應(yīng)用,本文首先從前端路由的原理出發(fā),詳細(xì)介紹了前端路由原理的變遷。接著從react-router4.0的源碼出發(fā),深入理解react-router4.0是如何實(shí)現(xiàn)前端路由的。

通過Hash實(shí)現(xiàn)前端路由

通過H5的history實(shí)現(xiàn)前端路由

React-router4.0的使用

React-router4.0源碼分析

原文的地址,在我的博客中:https://github.com/forthealll...

如有幫助,您的star是對(duì)我最好的鼓勵(lì)~

一、通過Hash實(shí)現(xiàn)前端路由 1、hash的原理

??早期的前端路由是通過hash來實(shí)現(xiàn)的:

改變url的hash值是不會(huì)刷新頁面的。

??因此可以通過hash來實(shí)現(xiàn)前端路由,從而實(shí)現(xiàn)無刷新的效果。hash屬性位于location對(duì)象中,在當(dāng)前頁面中,可以通過:

window.location.hash="edit"

來實(shí)現(xiàn)改變當(dāng)前url的hash值。執(zhí)行上述的hash賦值后,頁面的url發(fā)生改變。

賦值前:http://localhost:3000
賦值后:http://localhost:3000/#edit

在url中多了以#結(jié)尾的hash值,但是賦值前后雖然頁面的hash值改變導(dǎo)致頁面完整的url發(fā)生了改變,但是頁面是不會(huì)刷新的。此外,還有一個(gè)名為hashchange的事件,可以監(jiān)聽hash的變化,我們可以通過下面兩種方式來監(jiān)聽hash的變化:

window.onhashchange=function(event){
   console.log(event);
}
window.addEventListener("hashchange",function(event){
   console.log(event);
})

當(dāng)hash值改變時(shí),輸出一個(gè)HashChangeEvent。該HashChangeEvent的具體值為:

{isTrusted: true, oldURL: "http://localhost:3000/", newURL:   "http://localhost:3000/#teg", type: "hashchange".....}

??有了監(jiān)聽事件,且改變hash頁面不刷新,這樣我們就可以在監(jiān)聽事件的回調(diào)函數(shù)中,執(zhí)行我們展示和隱藏不同UI顯示的功能,從而實(shí)現(xiàn)前端路由。

此外,除了可以通過window.location.hash來改變當(dāng)前頁面的hash值外,還可以通過html的a標(biāo)簽來實(shí)現(xiàn):

edit
2、hash的缺點(diǎn)

hash的兼容性較好,因此在早期的前端路由中大量的采用,但是使用hash也有很多缺點(diǎn)。

搜索引擎對(duì)帶有hash的頁面不友好

帶有hash的頁面內(nèi)難以追蹤用戶行為

二、通過history實(shí)現(xiàn)前端路由

HTML5的History接口,History對(duì)象是一個(gè)底層接口,不繼承于任何的接口。History接口允許我們操作瀏覽器會(huì)話歷史記錄。

(1)History的屬性和方法

History提供了一些屬性和方法。

History的屬性:

History.length: 返回在會(huì)話歷史中有多少條記錄,包含了當(dāng)前會(huì)話頁面。此外如果打開一個(gè)新的Tab,那么這個(gè)length的值為1

History.state:

保存了會(huì)出發(fā)popState事件的方法,所傳遞過來的屬性對(duì)象(后面會(huì)在pushState和replaceState方法中詳細(xì)的介紹)

History方法:

History.back(): 返回瀏覽器會(huì)話歷史中的上一頁,跟瀏覽器的回退按鈕功能相同

History.forward():指向?yàn)g覽器會(huì)話歷史中的下一頁,跟瀏覽器的前進(jìn)按鈕相同

History.go(): 可以跳轉(zhuǎn)到瀏覽器會(huì)話歷史中的指定的某一個(gè)記錄頁

History.pushState():pushState可以將給定的數(shù)據(jù)壓入到瀏覽器會(huì)話歷史棧中,該方法接收3個(gè)參數(shù),對(duì)象,title和一串url。pushState后會(huì)改變當(dāng)前頁面url,但是不會(huì)伴隨著刷新

History.replaceState():replaceState將當(dāng)前的會(huì)話頁面的url替換成指定的數(shù)據(jù),replaceState后也會(huì)改變當(dāng)前頁面的url,但是也不會(huì)刷新頁面。

上面的方法中,pushState和repalce的相同點(diǎn):

就是都會(huì)改變當(dāng)前頁面顯示的url,但都不會(huì)刷新頁面。

不同點(diǎn):

pushState是壓入瀏覽器的會(huì)話歷史棧中,會(huì)使得History.length加1,而replaceState是替換當(dāng)前的這條會(huì)話歷史,因此不會(huì)增加History.length.

(2)BOM對(duì)象history

history在瀏覽器的BOM對(duì)象模型中的重要屬性,history完全繼承了History接口,因此擁有History中的所有的屬性和方法。

這里我們主要來看看history.length屬性以及history.pushState、history.replaceState方法。

history.pushState(stateObj,title,url) or history.replaceState(stateObj,title,url)

pushState和replaceState接受3個(gè)參數(shù),分別為state對(duì)象,title標(biāo)題,改變的url。

window.history.pushState({foo:"bar"}, "page 2", "bar.html");

此時(shí),當(dāng)前的url變?yōu)椋?/p>

執(zhí)行上述方法前:http://localhost:3000
執(zhí)行上述方法后:http://localhost:3000/bar.html

如果我們輸出window.history.state:

console.log(window.history.state);
// {foo:"bar"}

window.history.state就是我們pushState的第一個(gè)對(duì)象參數(shù)。

history.replaceState()方法不會(huì)改變hitroy的長度

console.log(window.history.length);
window.history.replaceState({foo:"bar"}, "page 2", "bar.html");
console.log(window.history.length);

上述前后兩次輸出的window.history.length是相等的。

此外。

每次觸發(fā)history.back()或者瀏覽器的后退按鈕等,會(huì)觸發(fā)一個(gè)popstate事件,這個(gè)事件在后退或者前進(jìn)的時(shí)候發(fā)生:

window.onpopstate=function(event){

}

注意:
history.pushState和history.replaceState方法并不會(huì)觸發(fā)popstate事件。

如果用history做為路由的基礎(chǔ),那么需要用到的是history.pushState和history.replaceState,在不刷新的情況下可以改變url的地址,且如果頁面發(fā)生回退back或者forward時(shí),會(huì)觸發(fā)popstate事件。

hisory為依據(jù)來實(shí)現(xiàn)路由的優(yōu)點(diǎn):

對(duì)搜索引擎友好

方便統(tǒng)計(jì)用戶行為

缺點(diǎn):

兼容性不如hash

需要后端做相應(yīng)的配置,否則直接訪問子頁面會(huì)出現(xiàn)404錯(cuò)誤

三、React-router4.0的使用

了解了前端路由實(shí)現(xiàn)的原理之后,下面來介紹一下React-router4.0。在React-router4.0的代碼庫中,根據(jù)使用場景包含了以下幾個(gè)獨(dú)立的包:

react-router : react-router4.0的核心代碼

react-router-dom : 構(gòu)建網(wǎng)頁應(yīng)用,存在DOM對(duì)象場景下的核心包

react-router-native : 適用于構(gòu)建react-native應(yīng)用

react-router-config : 配置靜態(tài)路由

react-router-redux : 結(jié)合redux來配置路由,已廢棄,不推薦使用。

在react-router4.0中,遵循Just Component的設(shè)計(jì)理念:

所提供的API都是以組件的形式給出。

比如BrowserRouter、Router、Link、Switch等API都是以組件的形式來使用。

1、React-router-dom常用的組件API

下面我們以React-router4.0中的React-router-dom包來介紹常用的BrowserRouter、HashRouter、Link和Router等。

(1)

組件包裹整個(gè)App系統(tǒng)后,就是通過html5的history來實(shí)現(xiàn)無刷新條件下的前端路由。

組件具有以下幾個(gè)屬性:

basename: string 這個(gè)屬性,是為當(dāng)前的url再增加名為basename的值的子目錄。

 

如果設(shè)置了basename屬性,那么此時(shí)的:

http://localhost:3000 和 http://localhost:3000/test 表示的是同一個(gè)地址,渲染的內(nèi)容相同。

getUserConfirmation: func 這個(gè)屬性,用于確認(rèn)導(dǎo)航的功能。默認(rèn)使用window.confirm

forceRefresh: bool 默認(rèn)為false,表示改變路由的時(shí)候頁面不會(huì)重新刷新,如果當(dāng)前瀏覽器不支持history,那么當(dāng)forceRefresh設(shè)置為true的時(shí)候,此時(shí)每次去改變url都會(huì)重新刷新整個(gè)頁面。

keyLength: number 表示location的key屬性的長度,在react-router中每個(gè)url下都有為一個(gè)location與其對(duì)應(yīng),并且每一個(gè)url的location的key值都不相同,這個(gè)屬性一般都使用默認(rèn)值,設(shè)置的意義不大。

children: node children的屬性必須是一個(gè)ReactNode節(jié)點(diǎn),表示唯一渲染一個(gè)元素。

對(duì)應(yīng)的是,使用url中的hash屬性來保證不重新刷新的情況下同時(shí)渲染頁面。

(2)

組件十分重要, 做的事情就是匹配相應(yīng)的location中的地址,匹配成功后渲染對(duì)應(yīng)的組件。下面我們來看中的屬性。

首先來看如何執(zhí)行匹配,決定地址匹配的屬性:

path:當(dāng)location中的url改變后,會(huì)與Route中的path屬性做匹配,path決定了與路由或者url相關(guān)的渲染效果。

exact: 如果有exact,只有url地址完全與path相同,才會(huì)匹配。如果沒有exact屬性,url的地址不完全相同,也會(huì)匹配。

舉例來說,當(dāng)exact不設(shè)置時(shí):

 
 

此時(shí)url地址為:http://localhost:3000/home/first 的時(shí)候,不僅僅會(huì)匹配到 path="/home/first"時(shí)的組件First,同時(shí)還會(huì)匹配到path="home"時(shí)候的Router。

如果設(shè)置了exact:

  

只有http://localhost:3000/home/first 不會(huì)匹配Home組件,只有url地址完全與path相同,只有http://localhost:3000/home才能匹配Home組件成功。

strict :與exact不同,strict屬性僅僅是對(duì)exact屬性的一個(gè)補(bǔ)充,設(shè)置了strict屬性后,嚴(yán)格限制了但斜線“/”。

舉例來說,當(dāng)不設(shè)置strict的時(shí)候:

  

此時(shí)http://localhost:3000/home 和 http://localhost:3000/home/
都能匹配到組件Home。匹配對(duì)于斜線“/”比較寬松。如果設(shè)置了strict屬性:

 

那么此時(shí)嚴(yán)格匹配斜線是否存在,http://localhost:3000/home 將無法匹配到Home組件。

當(dāng)Route組件與某一url匹配成功后,就會(huì)繼續(xù)去渲染。那么什么屬性決定去渲染哪個(gè)組件或者樣式呢,Route的component、render、children決定渲染的內(nèi)容。

component:該屬性接受一個(gè)React組件,當(dāng)url匹配成功,就會(huì)渲染該組件

render:func 該屬性接受一個(gè)返回React Element的函數(shù),當(dāng)url匹配成功,渲染覆該返回的元素

children:與render相似,接受一個(gè)返回React Element的函數(shù),但是不同點(diǎn)是,無論url與當(dāng)前的Route的path匹配與否,children的內(nèi)容始終會(huì)被渲染出來。

并且這3個(gè)屬性所接受的方法或者組件,都會(huì)有l(wèi)ocation,match和history這3個(gè)參數(shù)。如果組件,那么組件的props中會(huì)存在從Link傳遞過來的location,match以及history。

(3)

定義了匹配規(guī)則和渲染規(guī)則,而 決定的是如何在頁面內(nèi)改變url,從而與相應(yīng)的匹配。類似于html中的a標(biāo)簽,此外在改變url的時(shí)候,可以將一些屬性傳遞給匹配成功的Route,供相應(yīng)的組件渲染的時(shí)候使用。

to: string

to屬性的值可以為一個(gè)字符串,跟html中的a標(biāo)簽的href一樣,即使to屬性的值是一個(gè)字符串,點(diǎn)擊Link標(biāo)簽跳轉(zhuǎn)從而匹配相應(yīng)path的Route,也會(huì)將history,location,match這3個(gè)對(duì)象傳遞給Route所對(duì)應(yīng)的組件的props中。

舉例來說:

Home

如上所示,當(dāng)to接受一個(gè)string,跳轉(zhuǎn)到url為"/home"所匹配的Route,并渲染其關(guān)聯(lián)的組件內(nèi)接受3個(gè)對(duì)象history,location,match。
這3個(gè)對(duì)象會(huì)在下一小節(jié)會(huì)詳細(xì)介紹。

to: object

to屬性的值也可以是一個(gè)對(duì)象,該對(duì)象可以包含一下幾個(gè)屬性:pathname、seacth、hash和state,其中前3個(gè)參數(shù)與如何改變url有關(guān),最后一個(gè)state參數(shù)是給相應(yīng)的改變url時(shí),傳遞一個(gè)對(duì)象參數(shù)。

舉例來說:

 Home
 

在上個(gè)例子中,to為一個(gè)對(duì)象,點(diǎn)擊Link標(biāo)簽跳轉(zhuǎn)后,改變后的url為:"/home?sort=name#edit"。 但是在與相應(yīng)的Route匹配時(shí),只匹配path為"/home"的組件,"/home?sort=name#edit"。在"/home"后所帶的參數(shù)不作為匹配標(biāo)準(zhǔn),僅僅是做為參數(shù)傳遞到所匹配到的組件中,此外,state={a:1}也同樣做為參數(shù)傳遞到新渲染的組件中。

(4) React-router中傳遞給組件props的history對(duì)象

介紹了 、 之后,使用這3個(gè)組件API就可以構(gòu)建一個(gè)簡單的React-router應(yīng)用。這里我們之前說,每當(dāng)點(diǎn)擊Link標(biāo)簽跳轉(zhuǎn)或者在js中使用React-router的方法跳轉(zhuǎn),從當(dāng)前渲染的組件,進(jìn)入新組件。在新組件被渲染的時(shí)候,會(huì)接受一個(gè)從舊組件傳遞過來的參數(shù)。

我們前面提到,Route匹配到相應(yīng)的改變后的url,會(huì)渲染新組件,該新組件中的props中有history、location、match3個(gè)對(duì)象屬性,其中hisotry對(duì)象屬性最為關(guān)鍵。

同樣以下面的例子來說明:

Home



我們使用了,該組件利用了window.history對(duì)象,當(dāng)點(diǎn)擊Link標(biāo)簽跳轉(zhuǎn)后,會(huì)渲染新的組件Home,我們可以在Home組件中輸出props中的history:

// props中的history
action: "PUSH"
block: ? block()
createHref: ? createHref(location)
go: ? go(n)
goBack: ? goBack()
goForward: ? goForward()
length: 12
listen: ? listen(listener)
location: {pathname: "/home", search: "?sort=name", hash: "#edit", state: {…}, key: "uxs9r5"}
push: ? push(path, state)
replace: ? replace(path, state)

從上面的屬性明細(xì)中:

push:f 這個(gè)方法用于在js中改變url,之前在Link組件中可以類似于HTML標(biāo)簽的形式改變url。push方法映射于window.history中的pushState方法。

replace: f 這個(gè)方法也是用于在js中改變url,replace方法映射于window.history中的replaceState方法。

block:f 這個(gè)方法也很有用,比如當(dāng)用戶離開當(dāng)前頁面的時(shí)候,給用戶一個(gè)文字提示,就可以采用history.block("你確定要離開當(dāng)前頁嗎?")這樣的提示。

go / goBack / goForward

在組件props中history的go、goBack、goForward方法,分別window.history.go、window.history.back、window.history.forward對(duì)應(yīng)。

action: "PUSH" || "POP"

action這個(gè)屬性左右很大,如果是通過Link標(biāo)簽或者在js中通過this.props.push方法來改變當(dāng)前的url,那么在新組件中的action就是"PUSH",否則就是"POP".

action屬性很有用,比如我們在做翻頁動(dòng)畫的時(shí)候,前進(jìn)的動(dòng)畫是SlideIn,后退的動(dòng)畫是SlideOut,我們可以根據(jù)組件中的action來判斷采用何種動(dòng)畫:

function newComponent (props)=>{
   return (
     
           
    
   )
}

location:object

在新組件的location屬性中,就記錄了從就組件中傳遞過來的參數(shù),從上面的例子中,我們看到此時(shí)的location的值為:

    hash: "#edit"
    key: "uxs9r5"
    pathname: "/home"
    search: "?sort=name"
    state: {a:1}
    

除了key這個(gè)用作唯一表示外,其他的屬性都是我們從上一個(gè)Link標(biāo)簽中傳遞過來的參數(shù)。

四、React-router4.0源碼分析

在第三節(jié)中我們介紹了React-router的大致使用方法,讀一讀React-router4.0的源碼。

這里我們主要分析一下React-router4.0中是如何根據(jù)window.history來實(shí)現(xiàn)前端路由的,因此設(shè)計(jì)到的組件為BrowserRouter、Router、Route和Link

1、React-router中的history

從上一節(jié)的介紹中我們知道,點(diǎn)擊Link標(biāo)簽傳遞給新渲染的組件的props中有一個(gè)history對(duì)象,這個(gè)對(duì)象的內(nèi)容很豐富,比如:action、goBack、go、location、push和replace方法等。

React-router構(gòu)建了一個(gè)History類,用于在window.history的基礎(chǔ)上,構(gòu)建屬性更為豐富的實(shí)例。該History類實(shí)例化后具有action、goBack、location等等方法。

React-router中將這個(gè)新的History類的構(gòu)建方法,獨(dú)立成一個(gè)node包,包名為history。

npm install history -s 

可以通過上述方法來引入,我們來看看這個(gè)History類的實(shí)現(xiàn)。

const createBrowserHistory = (props = {}) => {
    const globalHistory = window.history;
    ......
    //默認(rèn)props中屬性的值
    const {
      forceRefresh = false,
      getUserConfirmation = getConfirmation,
      keyLength = 6,
      basename = "",
    } = props;
    const history = {
        length: globalHistory.length,
        action: "POP",
        location: initialLocation,
        createHref,
        push,
        replace,
        go,
        goBack,
        goForward,
        block,
        listen
    };                                         ---- (1)
    const basename = props.basename;   
    const canUseHistory = supportsHistory();   ----(2)
            
    const createKey = () =>Math.random().toString(36).substr(2, keyLength);    ----(3)
    
    const transitionManager = createTransitionManager();  ----(4)
    const setState = nextState => {
        Object.assign(history, nextState);
    
        history.length = globalHistory.length;
    
        transitionManager.notifyListeners(history.location, history.action);
    };                                      ----(5)
    
    const handlePopState = event => {
        handlePop(getDOMLocation(event.state));
    };
    const handlePop = location => {
    if (forceNextPop) {
      forceNextPop = false;
      setState();
    } else {
      const action = "POP";
      
      transitionManager.confirmTransitionTo(
            location,
            action,
            getUserConfirmation,
            ok => {
              if (ok) {
                setState({ action, location });
              } else {
                revertPop(location);
              }
            }
          );
        }
    };                                    ------(6)
    const initialLocation = getDOMLocation(getHistoryState());
    let allKeys = [initialLocation.key]; ------(7)
    
  
    // 與pop相對(duì)應(yīng),類似的push和replace方法
    const push ... replace ...            ------(8)
    
    return history                        ------ (9)
    
}


(1) 中指明了新的構(gòu)建方法History所返回的history對(duì)象中所具有的屬性。

(2)中的supportsHistory的方法判斷當(dāng)前的瀏覽器對(duì)于window.history的兼容性,具體方法如下:

    export const supportsHistory = () => {
      const ua = window.navigator.userAgent;
    
      if (
        (ua.indexOf("Android 2.") !== -1 || ua.indexOf("Android 4.0") !== -1) &&
        ua.indexOf("Mobile Safari") !== -1 &&
        ua.indexOf("Chrome") === -1 &&
        ua.indexOf("Windows Phone") === -1
      )
        return false;
    
      return window.history && "pushState" in window.history;
    };

從上述判別式我們可以看出,window.history在chrome、mobile safari和windows phone下是絕對(duì)支持的,但不支持安卓2.x以及安卓4.0

(3)中用于創(chuàng)建與history中每一個(gè)url記錄相關(guān)聯(lián)的指定位數(shù)的唯一標(biāo)識(shí)key, 默認(rèn)的keyLength為6位

(4)中 createTransitionManager方法,返回一個(gè)集成對(duì)象,對(duì)象中包含了關(guān)于history地址或者對(duì)象改變時(shí)候的監(jiān)聽函數(shù)等,具體代碼如下:

     const createTransitionManager = () => {
         const setPrompt = nextPrompt => {
           
         };
   
         const confirmTransitionTo = (
           location,
           action,
           getUserConfirmation,
           callback
         ) => {
            if (typeof getUserConfirmation === "function") {
                 getUserConfirmation(result, callback);
               } else {
                 callback(true);
               }
             } 
         };
         
         
         let listeners = [];
         const appendListener = fn => {
           let isActive = true;
       
           const listener = (...args) => {
             if (isActive) fn(...args);
           };
       
           listeners.push(listener);
       
           return () => {
             isActive = false;
             listeners = listeners.filter(item => item !== listener);
           };
         };
       
         const notifyListeners = (...args) => {
           listeners.forEach(listener => listener(...args));
         };
       
         return {
           setPrompt,
           confirmTransitionTo,
           appendListener,
           notifyListeners
         };

};

setPrompt函數(shù),用于設(shè)置url跳轉(zhuǎn)時(shí)彈出的文字提示,confirmTransaction函數(shù),會(huì)將當(dāng)前生成新的history對(duì)象中的location,action,callback等參數(shù),作用就是在回調(diào)的callback方法中,根據(jù)要求,改變傳入的location和action對(duì)象。

接著我們看到有一個(gè)listeners數(shù)組,保存了一系列與url相關(guān)的監(jiān)聽事件數(shù)組,通過接下來的appendListener方法,可以往這個(gè)數(shù)組中增加事件,通過notifyListeners方法可以遍歷執(zhí)行l(wèi)isteners數(shù)組中的所有事件。

(5) setState方法,發(fā)生在history的url或者h(yuǎn)istory的action發(fā)生改變的時(shí)候,此方法會(huì)更新history對(duì)象中的屬性,同時(shí)會(huì)觸發(fā)notifyListeners方法,傳入當(dāng)前的history.location和history.action。遍歷并執(zhí)行所有監(jiān)聽url改變的事件數(shù)組listeners。

(6)這個(gè)getDOMLocation方法就是根據(jù)當(dāng)前在window.state中的值,生成新history的location屬性對(duì)象,allKeys這是始終保持了在url改變時(shí)候的歷史url相關(guān)聯(lián)的key,保存在全局,allKeys在執(zhí)行生“POP”或者“PUSH”、“Repalce”等會(huì)改變url的方法時(shí),會(huì)保持一個(gè)實(shí)時(shí)的更新。

(7) handlePop方法,用于處理“POP”事件,我們知道在window.history中點(diǎn)擊后退等會(huì)觸發(fā)“POP”事件,這里也是一樣,執(zhí)行action為“POP”,當(dāng)后退的時(shí)候就會(huì)觸發(fā)該函數(shù)。

(8)中包含了與pop方法類似的,push和replace方法,push方法同樣做的事情就是執(zhí)行action為“PUSH”(“REPLACE”),該變allKeys數(shù)組中的值,唯一不同的是actio為“PUSH”的方法push是往allKeys數(shù)組中添加,而action為“REPLACE”的方法replace則是替換掉當(dāng)前的元素。

(9)返回這個(gè)新生成的history對(duì)象。

2、React-router中Link組件

其實(shí)最難弄懂的是React-router中如何重新構(gòu)建了一個(gè)history工廠函數(shù),在第一小節(jié)中我們已經(jīng)詳細(xì)的介紹了history生成函數(shù)createBrowserHistory的源碼,接著來看Link組件就很容易了。

首先Link組件類似于HTML中的a標(biāo)簽,目的也很簡單,就是去主動(dòng)觸發(fā)改變url的方法,主動(dòng)改變url的方法,從上述的history的介紹中可知為push和replace方法,因此Link組件的源碼為:

class Link extends React.Component {

    
   handleClick = event => {
   ...

     const { history } = this.context.router;
     const { replace, to } = this.props;
     if (replace) {
       history.replace(replace);
     } else {
      history.push(to);
     }
   }
  };
  render(){
    const { replace, to, innerRef, ...props } = this.props;
     
  }
}

上述代碼很簡單,從React的context API全局對(duì)象中拿到history,然后如果傳遞給Link組件的屬性中有replace為true,則執(zhí)行history.replace(to),to 是一個(gè)包含pathname的對(duì)象,如果傳遞給Link組件的replace屬性為false,則執(zhí)行history.push(to)方法。

3、React-router中Route組件

Route組件也很簡單,其props中接受一個(gè)最主要的屬性path,Route做的事情只有一件:

當(dāng)url改變的時(shí)候,將path屬性與改變后的url做對(duì)比,如果匹配成功,則渲染該組件的componet或者children屬性所賦值的那個(gè)組件。

具體源碼如下:

class Route extends React.Component {


  ....
  constructor(){
  
  
  }
  render() {
    const { match } = this.state;
    const { children, component, render } = this.props;
    const { history, route, staticContext } = this.context.router;
    const location = this.props.location || route.location;
    const props = { match, location, history, staticContext };

    if (component) return match ? React.createElement(component, props) : null;

    if (render) return match ? render(props) : null;

    if (typeof children === "function") return children(props);

    if (children && !isEmptyChildren(children))
      return React.Children.only(children);

    return null;
  }

}

state中的match就是是否匹配的標(biāo)記,如果匹配當(dāng)前的Route的path,那么根據(jù)優(yōu)先級(jí)順序component屬性、render屬性和children屬性來渲染其所指向的React組件。

4、React-router中Router組件

Router組件中,是BrowserRouter、HashRouter等組件的底層組件。該組件中,定義了包含匹配規(guī)則match函數(shù),以及使用了新history中的listener方法,來監(jiān)聽url的改變,從而,當(dāng)url改變時(shí),更改Router下不同path組件的isMatch結(jié)果。

class Router extends React.Component {
    componentWillMount() {
        const { children, history } = this.props
        
        //調(diào)用history.listen監(jiān)聽方法,該方法的返回函數(shù)是一個(gè)移除監(jiān)聽的函數(shù)
        
        this.unlisten = history.listen(() => {
          this.setState({
            match: this.computeMatch(history.location.pathname)
          });
        });
    }
    componentWillUnmount() {
      this.unlisten();
    }
    render() {
    
    }
}

上述首先在組件創(chuàng)建前調(diào)用了listener監(jiān)聽方法,來監(jiān)聽url的改變,實(shí)時(shí)的更新isMatch的結(jié)果。

5、總結(jié)

本文從前端路由的原理出發(fā),先后介紹了兩種前端路由常用的方法,接著介紹了React-router的基本組件API以及用法,詳細(xì)介紹了React-router的組件中新構(gòu)建的history對(duì)象,最后結(jié)合React-router的API閱讀了一下React-router的源碼。

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/97860.html

相關(guān)文章

  • 前端路由實(shí)現(xiàn)與 react-router 源碼分析

    摘要:回調(diào)函數(shù)將在更新時(shí)觸發(fā),回調(diào)中的起到了新的的作用。注冊回調(diào)在中使用注冊的回調(diào)函數(shù),最終放在模塊的回調(diào)函數(shù)數(shù)組中。 原文地址:https://github.com/joeyguo/blog/issues/2 在單頁應(yīng)用上,前端路由并不陌生。很多前端框架也會(huì)有獨(dú)立開發(fā)或推薦配套使用的路由系統(tǒng)。那么,當(dāng)我們在談前端路由的時(shí)候,還可以談些什么?本文將簡要分析并實(shí)現(xiàn)一個(gè)的前端路由,并對(duì) reac...

    ISherry 評(píng)論0 收藏0
  • 深入redux技術(shù)棧

    摘要:另外,內(nèi)置的函數(shù)在經(jīng)過一系列校驗(yàn)后,觸發(fā),之后被更改,之后依次調(diào)用監(jiān)聽,完成整個(gè)狀態(tài)樹的更新??偠灾?,遵守這套規(guī)范并不是強(qiáng)制性的,但是項(xiàng)目一旦稍微復(fù)雜一些,這樣做的好處就可以充分彰顯出來。 這一篇是接上一篇react進(jìn)階漫談的第二篇,這一篇主要分析redux的思想和應(yīng)用,同樣參考了網(wǎng)絡(luò)上的大量資料,但代碼同樣都是自己嘗試實(shí)踐所得,在這里分享出來,僅供一起學(xué)習(xí)(上一篇地址:個(gè)人博客/s...

    imingyu 評(píng)論0 收藏0
  • 深入redux技術(shù)棧

    摘要:另外,內(nèi)置的函數(shù)在經(jīng)過一系列校驗(yàn)后,觸發(fā),之后被更改,之后依次調(diào)用監(jiān)聽,完成整個(gè)狀態(tài)樹的更新。總而言之,遵守這套規(guī)范并不是強(qiáng)制性的,但是項(xiàng)目一旦稍微復(fù)雜一些,這樣做的好處就可以充分彰顯出來。 這一篇是接上一篇react進(jìn)階漫談的第二篇,這一篇主要分析redux的思想和應(yīng)用,同樣參考了網(wǎng)絡(luò)上的大量資料,但代碼同樣都是自己嘗試實(shí)踐所得,在這里分享出來,僅供一起學(xué)習(xí)(上一篇地址:個(gè)人博客/s...

    VPointer 評(píng)論0 收藏0
  • 手挽手帶你學(xué)React:三檔 React-router4.x使用

    摘要:我們在內(nèi)部來渲染不同的組件我們這里采用哈希路由的方式,鑒于的渲染機(jī)制,我們需要把值綁定進(jìn)入內(nèi)部。 手挽手帶你學(xué)React入門三檔,帶你學(xué)會(huì)使用Reacr-router4.x,開始創(chuàng)建屬于你的React項(xiàng)目 什么是React-router React Router 是一個(gè)基于 React 之上的強(qiáng)大路由庫,它可以讓你向應(yīng)用中快速地添加視圖和數(shù)據(jù)流,同時(shí)保持頁面與 URL 間的同步。通俗一...

    SunZhaopeng 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

最新活動(dòng)
閱讀需要支付1元查看
<