React中的路由react-router

URL的hash

  • URL的hash就是錨點,本質上是改變window.location的href屬性;
  • 我們可以直接賦值location.hash來改變href,但是頁面不發生刷新;
<body>
    <div id="app">
        <a href="#/home">首頁</a>
        <a href="#/about">關于</a>

        <div class="router-view"></div>
    </div>
</body>
<script>
    const routerView = document.getElementsByClassName("router-view")[0];

    //監聽URL的改變
    window.addEventListener("hashchange",()=>{
        switch(location.hash){
            case "#/home":
                routerView.innerHTML = "首頁";
                break;
            case "#/about":
                routerView.innerHTML = "關于";
                break;
            default:
                routerView.innerHTML = "";
        }
    })
</script>

HTML5的history

  • history接口是HTML5新增的,它有六種模式改變URL而不刷新頁面;
方法 解釋
history.back() 在瀏覽器歷史記錄里前往上一頁, 用戶可點擊瀏覽器左上角的返回(譯者注:←)按鈕模擬此方法. 等價于 history.go(-1)
history.forward() 在瀏覽器歷史記錄里前往下一頁,用戶可點擊瀏覽器左上角的前進(譯者注:→)按鈕模擬此方法. 等價于 history.go(1)
history.go() 通過當前頁面的相對位置從瀏覽器歷史記錄( 會話記錄 )加載頁面。比如:參數為-1的時候為上一頁,參數為1的時候為下一頁.
history.pushState() 按指定的名稱和URL(如果提供該參數)將數據push進會話歷史棧,數據被DOM進行不透明處理;你可以指定任何可以被序列化的javascript對象
history.replaceState() 按指定的數據,名稱和URL(如果提供該參數),更新歷史棧上最新的入口。這個數據被DOM 進行了不透明處理。你可以指定任何可以被序列化的javascript對象。
<body>
    <div>
        <div id="app">
            <a href="/home">首頁</a>
            <a href="/about">關于</a>

            <div class="router-view"></div>
        </div>
    </div>
    <script>

        const routerView = document.getElementsByClassName("router-view")[0];

        const aEL = document.getElementsByTagName("a");
        for (let i = 0; i < aEL.length; i++) {
            aEL[i].addEventListener("click", e => {
                e.preventDefault();
                const href = aEL[i].getAttribute("href");
                history.pushState({}, "", href);
                urlChange();
            })
        }
        // for(let el of aEL){
        //     el.addEventListener("click",e => {
        //         e.preventDefault();
        //         const href = el.getAttribute("href");
        //         history.pushState({},"",href);
        //     })
        // }

        //執行返回操作時,依然來到urlChange
        window.addEventListener("popstate",urlChange);

        function urlChange() {
            switch (location.pathname) {
                case "/home":
                    routerView.innerHTML = "首頁";
                    break;
                case "/about":
                    routerView.innerHTML = "關于";
                    break;
                default:
                    routerView.innerHTML = "";
            }
        }

    </script>
</body>

Router的基本使用

react-router最主要的API是給我們提供的一些組件:

  • BrowserRouter或HashRouter
    \triangleright Router中包含了對路徑改變的監聽,并且會將相應的路徑傳遞給子組件;
    \triangleright BrowserRouter使用history模式;
    \triangleright HashRouter使用hash模式;
  • Link和NavLink
    \triangleright 通常路徑的跳轉是使用Link組件,最終會被渲染成a元素;
    \triangleright NavLink是在Link基礎上增加了一些樣式屬性;
    \triangleright to屬性:Link中最重要的屬性,用于設置跳轉到的路徑;
  • Route
    \triangleright Route用于路徑的匹配;
    \triangleright path屬性:用于設置匹配到的路徑;
    \triangleright component屬性:設置匹配到路徑后,渲染的組件;
    \triangleright exact:精準匹配,只有精準匹配到完全一致的路徑,才會渲染對應的組件;

NavLink組件的使用

<NavLink>是<Link>的特定版本,會在匹配上當前的url的時候給已渲染的元素添加參數

  • activeStyle(object):當元素被選中時,為此元素添加樣式
  • activeClassName(string):設置選中樣式,默認值為active
  • exact(boolean):是否精準匹配
    \triangleright 注意:在組件添加exact屬性,能夠讓路由精準匹配到url
    \triangleright 若不添加exact屬性的話,在"/about"的組件和"/profile"組件中也會渲染出"/"的組件
<NavLink  exact to="/" activeStyle={{color:"blue"}}>首頁</NavLink>
<NavLink to="/about"  activeStyle={{color:"blue"}}>關于</NavLink>
<NavLink to="/profile"  activeStyle={{color:"blue"}}>首頁</NavLink>

Switch組件的使用

  • 渲染第一個被location匹配到的并且作為子元素的<Route>或者<Redirect>

問題:在/about路徑匹配到的同時,/:userid也被匹配到,并且最后一個NoMatch組件總是被匹配到,這該如何解決?

    <Route exact path="/" exact component={home} />
    <Route path="/about" component={about} />
    <Route path="/profile" component={profile} />
    <Route path="/:id" component={user} />
    <Route path="/user" component={noMatch} />

答:這個時候可以用Switch組件將所有的Route組件進行包裹。

<Switch>
    <Route exact path="/" exact component={home} />
    <Route path="/about" component={about} />
    <Route path="/profile" component={profile} />
    <Route path="/:id" component={user} />
    <Route path="/user" component={noMatch} />
</Switch>

Redirect組件的使用

  • Redirect用于路由的重定向,它會執行跳轉到對應的to路徑中
import React, { PureComponent } from 'react'
import { Redirect } from 'react-router-dom';

export default class user extends PureComponent {
    constructor(props){
        super(props);
        this.state ={
            isLogin: true
        }
    }

    render() {
        return this.state.isLogin ? (
            <div>
                <h2>user</h2>
                <h2>用戶名:boge</h2>
            </div>
        ) : <Redirect to="/login" />
    }
}

手動實現路由跳轉

比如,若想實現一個普通組件(button按鈕)點擊進行路由的跳轉的時候,要滿足兩個條件:

  • 普通組件必須包裹在Router組件之內;
  • 普通組件使用withRouter高階組件包裹;

src/App.js文件

import React, { PureComponent } from 'react'
import {withRouter} from 'react-router-dom'
class App extends PureComponent {}
export default withRouter(App);

src/index.js文件

import React from 'react';
import ReactDOM from 'react-dom';
import { BrowserRouter } from 'react-router-dom';

import App from './App';

ReactDOM.render(
  <BrowserRouter>  //這里要包裹一個Router組件才能使用withRouter高階組件
    <App />
  </BrowserRouter>,
  document.getElementById('root')
);

動態路由

傳遞參數有三種方式:

  • 動態路由的方式;
  • search傳遞參數;
  • Link中to傳入對象;

動態路由的概念--指的是路由中的路徑不是固定的:

  • 動態路由方式
    \triangleright 假如/detail的路徑對應 一個組件Detail
    \triangleright 若將路徑中的Route匹配時寫成/detail/:id,那么/detail/123,/detail/xyz都可以匹配到該Route并進行顯示
 <NavLink to="/detail/abc123">詳情</NavLink>

 <Route path="/detail/:id" component={detail} />
  • search傳遞參數
<NavLink to="/detail2?name=boge&age=20">詳情2</NavLink>
  • Link中to傳入對象
<NavLink to={{
     pathname: "/detail2",
     search:"?name=abc",
     state: id
}}>詳情3</NavLink>

react-router-config

若希望將所有的路由配置放到一個地方進行集中管理,這個時候可以使用react-router-config來完成。

  • yarn add react-router-config
  • 配置路由映射的關系數組

src/router/index.js文件

import home from '../pages/home';
import about,{AboutHistory,AboutCulture,AboutContact,AboutJoin} from '../pages/about';

const  routes = [
   {
        path:"/",
        component:home,
        exact:true
    },
    {
        path:"/about",
        component:about,
        routes: [
            {
                path:"/about",
                component: AboutHistory,
                exact: true
            },
            {
                path:"/about/culture",
                component: AboutCulture,
            },
            {
                path:"/about/contact",
                component: AboutContact,
            },
            {
                path:"/about/join",
                component: AboutJoin,
            }
        ]
    }
]
export default routes;
  • 使用renderRoutes函數完成配置

src/App.js文件

import React, { PureComponent } from 'react';
import {NavLink,withRouter} from 'react-router-dom';
import { renderRoutes} from 'react-router-config';
import routes from './router';

App extends PureComponent {
    render() {
        const id = "abc"
        return (
            <div>
                <NavLink exact to="/" activeClassName="link-active">首頁</NavLink>
                <NavLink to="/about" activeClassName="link-active">關于</NavLink>
                <NavLink to="/profile" activeClassName="link-active">我的</NavLink>
                <NavLink to="/user" activeClassName="link-active">用戶</NavLink>
                <NavLink to={`/detail/${id}`} activeClassName="link-active">詳情</NavLink>
                <NavLink to={{
                    pathname: "/detail2",
                    search:"?name=abc",
                    state: id
                }} activeClassName="link-active">詳情3</NavLink>
                <button onClick={e => this.ToProduct()}>商品</button>
                {renderRoutes(routes)}
            </div>
        )
    }
    ToProduct(){
        this.props.history.push("/product");
    }
}
export default withRouter(App);
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容