前端路由原理及react-router的常用組件

在react中,通常都是使用單頁(yè)面應(yīng)用(SPA),即整個(gè)頁(yè)面只有一個(gè)html,然后通過(guò)不同的url地址進(jìn)行組件的匹配和切換。

我們看到的url地址可能會(huì)有兩種形式,一種是 localhost:3000/home,一種是 localhost:3000/#/home,兩種地址的區(qū)別在于有無(wú)#,有#的是根據(jù)hash來(lái)進(jìn)行匹配,即url中的錨點(diǎn),本質(zhì)上是通過(guò)location.hash來(lái)改變href,hash后的內(nèi)容是不會(huì)發(fā)送給服務(wù)器的,沒(méi)有#是通過(guò)html5的history來(lái)進(jìn)行跳轉(zhuǎn),兩者跳轉(zhuǎn)后都不會(huì)進(jìn)行刷新。

具體來(lái)說(shuō),通過(guò)#來(lái)區(qū)分路由的實(shí)現(xiàn)原理是監(jiān)聽(tīng)hash的變化,這里監(jiān)聽(tīng)的方式是使用hashchange 事件,當(dāng)url地址發(fā)生了變化時(shí),通過(guò)匹配當(dāng)前url的地址來(lái)進(jìn)行展示,代碼如下所示

<body>
    <div>
       <a href="#/home">首頁(yè)</a>
       <a href="#/about">關(guān)于</a>
    </div>
    <div id="content"></div>

  <script>
    window.addEventListener('hashchange',()=>{
      const content = document.getElementById('content')
      switch(location.hash){
        case '#/home':
          content.innerHTML = '首頁(yè)'
          break
        case '#/about':
          content.innerHTML = '關(guān)于'
          break  
        default:  
          content.innerHTML = ''
      }
    })
  </script>
</body>

通過(guò)html5的history來(lái)實(shí)現(xiàn)跳轉(zhuǎn)無(wú)刷新,就需要阻止a標(biāo)簽的默認(rèn)行為,再通過(guò)history的pushState這一方法實(shí)現(xiàn)url地址的替換,同樣是監(jiān)聽(tīng)url地址的變化,這里使用popState方法,當(dāng)url地址發(fā)生了變化之后,展示對(duì)應(yīng)的內(nèi)容。

<body>
  <div>
    <div>
      <a href="/home">首頁(yè)</a>
      <a href="/about">關(guān)于</a>
    </div>
    <div id="content">
   </div>
</body>

<script>
  const content = document.getElementById('content')
  const aEles = document.getElementsByTagName('a')

  for (let el of aEles) {
    el.addEventListener('click', (event) => {
      event.preventDefault()
      const href = el.getAttribute("href")
      history.pushState({}, '', href)
      urlchange()
    })
  }

  window.addEventListener('popstate', () => {
    urlchange()
  })

  function urlchange() {
    switch (location.pathname) {
      case '/home':
        content.innerHTML = '首頁(yè)'
        break
      case '/about':
       content.innerHTML = '關(guān)于'
        break
      default:
        content.innerHTML = ''
    }
  }
</script>

以上的錨點(diǎn)和history分別對(duì)應(yīng)了react-router中的HashRouter和BrowserRouter,在react-router中,想要使用路由組件必須在最外層包裹一層HashRouter或者BrowserRouter,來(lái)選擇想要使用的路由類(lèi)型,然后才能使用react-router提供的其它組件,react-route中用于web端的庫(kù)為react-router-dom,以下所有的組件都是從react-router-dom中導(dǎo)出。

下面來(lái)說(shuō)說(shuō)react-router的常用組件

1、<Link>和<NavLink>,這兩個(gè)標(biāo)簽都是由a標(biāo)簽的封裝,通過(guò)to屬性指定跳轉(zhuǎn)的鏈接地址,<NavLink>比<Link>多的是可以指定選中的樣式和類(lèi)名,如

<Link to="/about">關(guān)于</Link>

通過(guò)<Link>標(biāo)簽,點(diǎn)擊之后就可以跳轉(zhuǎn)到指定的地址,此時(shí)即使外層包裹的是HashRouter,也不需要自己加上#,react-router會(huì)幫我們?cè)趗rl上加上#


hashRouter.png

2、當(dāng)使用<Link>定義了跳轉(zhuǎn)的url地址后,此時(shí)需要指定匹配跳轉(zhuǎn)該url地址時(shí)需要顯示的內(nèi)容,此時(shí)使用的是<Route>,通過(guò)path屬性指定url地址,component屬性指定渲染的組件,格式如

 <Route path="/about" component={About} />

加上了之后, /about這個(gè)地址顯示的就是About這個(gè)組件里的內(nèi)容。<Route>進(jìn)行的是模糊匹配,一個(gè)url路徑可能可以匹配多個(gè)Route,如果需要嚴(yán)格匹配的話,可以增加一個(gè)屬性 exact,適合沒(méi)有二級(jí)路由的時(shí)候開(kāi)啟。

3、在有很多的Route的情況下,即使在第一個(gè)Route匹配到合適的之后,仍然會(huì)繼續(xù)向下匹配,直到最后一個(gè),所以在所有的<Route>外包裹一個(gè)<Switch>標(biāo)簽可以讓它進(jìn)行唯一的匹配,匹配到合適的之后就不繼續(xù)匹配了。

4、當(dāng)所有的<Route>都無(wú)法匹配到url上的地址時(shí),可以定義 <Redirect>組件直接重定向到一個(gè)頁(yè)面,通過(guò)to來(lái)指定路由地址,這個(gè)組件要放置到<Route>的最后面,因?yàn)樗?lt;Link>不同,<Link>是點(diǎn)擊了之后才會(huì)跳轉(zhuǎn)對(duì)應(yīng)的地址,而<Redirect>會(huì)直接執(zhí)行并跳轉(zhuǎn)

<Redirect to="/about"/>

5、通過(guò)路由來(lái)匹配的組件稱(chēng)為路由組件,<Route path="/about" component={About} />,這里的About就是路由組件,和其它的組件是不一樣的,路由組件的props里有一些數(shù)據(jù),其中包括三大屬性,history、location和match,history可以自定義頁(yè)面的跳轉(zhuǎn),location用來(lái)獲取url地址相關(guān)的信息,match可以用作動(dòng)態(tài)路由的匹配。


props里傳遞的屬性.png

但一般的組件是沒(méi)有這些props屬性的,如果一般的組件也需要這樣一些屬性的話,可以通過(guò)一個(gè)高階組件 withRouter。如

class myCom extends PureComponent { }
export default withRouter(myCom)

再來(lái)說(shuō)說(shuō)路由傳參

有時(shí)候,我們希望在鏈接上帶一個(gè)id值或者兩個(gè)頁(yè)面之間跳轉(zhuǎn)的時(shí)候傳遞一些參數(shù),這時(shí)候有三種路由傳參方式

1、params傳參

<NavLink to="/detail/1">商品詳情</NavLink>
<Route path="/detail/:id" component={Detail}/>

// 如果是自行定義跳轉(zhuǎn)的地址可以通過(guò) this.props.history.push("/detail/1")

此時(shí)的id就是動(dòng)態(tài)的,可以在id這個(gè)位置傳遞任意的數(shù)值或者字符串,然后通過(guò)props里的match對(duì)象中的params獲取動(dòng)態(tài)匹配的內(nèi)容

2、search傳參

<NavLink to="/detail?id=1">商品詳情</NavLink>
<Route path="/detail" component={Detail}/>

// 如果是自行定義跳轉(zhuǎn)的地址可以通過(guò) this.props.history.push("/detail?id=1")

此時(shí)相當(dāng)于在url上添加一個(gè)問(wèn)號(hào)進(jìn)行拼接,需要把地址拼成一種鍵值對(duì)的形式,通過(guò) props里的location對(duì)象中的search屬性獲取從問(wèn)號(hào)開(kāi)始的匹配內(nèi)容,這一種路由的匹配方式需要自行解析字符串

3、state傳參

<NavLink to={ pathname: "/detail", state: { id: 1} }>商品詳情</NavLink>
<Route path="/detail" component={Detail}/>

// 如果是自行定義跳轉(zhuǎn)的地址可以通過(guò) this.props.history.push("/detail", { id: 1})

這樣的傳遞參數(shù)方式通過(guò)props里的location對(duì)象中的state屬性來(lái)獲取傳遞的值,這種方式的可以直接以對(duì)象的形式傳遞,并且可傳遞的數(shù)據(jù)更多,這些參數(shù)不會(huì)顯示在url上

用一個(gè)小的組合案例展示以上內(nèi)容

import React, { PureComponent } from 'react'
import { NavLink, Route, Switch, withRouter, Redirect } from "react-router-dom"
import Home from "./pages/Home"
import About from "./pages/About"
import Detail from "./pages/Detail"
import Product from './pages/Product'

class App extends PureComponent {
  jumpToProduct(){
    this.props.history.push('/product')
  }
  render() {
    return (
      <div>
        <NavLink exact to="/">首頁(yè)</NavLink>
        <NavLink to="/about">關(guān)于</NavLink>
        <NavLink to="/detail/1">詳情</NavLink>
        <button onClick={e=>this.jumpToProduct()}>商品</button>
        <Switch>
          <Route exact path="/" component={Home} />
          <Route path="/about" component={About} />
          <Route path="/detail/:id" component={Detail} />
          <Route path="/product" component={Product}/>
          <Redirect to="/"/>  
        </Switch>
      </div>
    );
  }
}

export default withRouter(App)
最后編輯于
?著作權(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)容

  • 原理 無(wú)刷新的更改地址欄地址 ,保證視圖和URL的同步。基本原理是H5History API 。瀏覽器的歷史記錄,...
    Kevin丶CK閱讀 3,760評(píng)論 0 3
  • 前端路由 在web應(yīng)用開(kāi)發(fā)中,路由系統(tǒng)是不可或缺的一部分。路由簡(jiǎn)單來(lái)說(shuō)就是當(dāng)url發(fā)生變化時(shí),web界面也會(huì)隨之改...
    我的秀閱讀 1,368評(píng)論 0 6
  • 一、如何找到文檔 在 GitHub 上直接搜索 react-router 進(jìn)入,就能找到開(kāi)發(fā)文檔,這里可以提供下,...
    CondorHero閱讀 535評(píng)論 0 1
  • URL的hash URL的hash就是錨點(diǎn),本質(zhì)上是改變window.location的href屬性; 我們可以直...
    腎仔博閱讀 26,122評(píng)論 1 1
  • ReactTraining/react-router的github地址: https://reacttrainin...
    wally210閱讀 1,306評(píng)論 0 0

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