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
Router中包含了對路徑改變的監聽,并且會將相應的路徑傳遞給子組件;
BrowserRouter使用history模式;
HashRouter使用hash模式;
-
Link和NavLink
通常路徑的跳轉是使用Link組件,最終會被渲染成a元素;
NavLink是在Link基礎上增加了一些樣式屬性;
to屬性:Link中最重要的屬性,用于設置跳轉到的路徑;
-
Route
Route用于路徑的匹配;
path屬性:用于設置匹配到的路徑;
component屬性:設置匹配到路徑后,渲染的組件;
exact:精準匹配,只有精準匹配到完全一致的路徑,才會渲染對應的組件;
NavLink組件的使用
<NavLink>是<Link>的特定版本,會在匹配上當前的url的時候給已渲染的元素添加參數
- activeStyle(object):當元素被選中時,為此元素添加樣式
- activeClassName(string):設置選中樣式,默認值為active
- exact(boolean):是否精準匹配
注意:在組件添加exact屬性,能夠讓路由精準匹配到url
若不添加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傳入對象;
動態路由的概念--指的是路由中的路徑不是固定的:
- 動態路由方式
假如/detail的路徑對應 一個組件Detail
若將路徑中的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);