react-router原理之路徑匹配一文中講了react-router如何根據url進行路徑匹配進而完成不一樣的組件渲染。接下來繼續講一下如何改變url。仍舊以官網爲例,演示地址react
const BasicExample = () => (
<Router>
<div>
<ul>
<li>
<Link to="/">Home</Link>
</li>
<li>
<Link to="/about">About</Link>
</li>
<li>
<Link to="/topics">Topics</Link>
</li>
</ul>
...
<Route exact path="/" component={Home} />
<Route path="/about" component={About} />
<Route path="/topics" component={Topics} />
</div>
</Router>
);
複製代碼
能夠看出Link的做用就是接受點擊而後觸發url地址的變動,Link組件最終在瀏覽器中是以何種方式存在的呢?經過查看頁面的Element能夠看到Link最終會轉成<a>標籤,上面的例子中的Link在瀏覽器中的樣子是這樣的web
<ul>
<li><a href="/">Home</a></li>
<li><a href="/about">About</a></li>
<li><a href="/topics">Topics</a></li>
</ul>
複製代碼
既然最終Link被轉換成上面<a>標籤的形式,那麼和代碼裏直接寫a標籤有什麼區別呢?npm
最大的區別表象體如今是否有主文檔請求,<a>標籤必定會出現,而Link則是一般不出現(除非特殊的配置)瀏覽器
Link在最後渲染的時候實際上是建立了<a>標籤,同時添加了一個onClick的監聽事件,onClick事件處理函數中作了兩件事:bash
render() {
....
return (
<a {...props} onClick={this.handleClick} href={href} ref={innerRef} />
);
}
handleClick = event => {
if (this.props.onClick) this.props.onClick(event);
if (
!event.defaultPrevented && // onClick prevented default
event.button === 0 && // ignore everything but left clicks
!this.props.target && // let browser handle "target=_blank" etc.
!isModifiedEvent(event) // ignore clicks with modifier keys
) {
event.preventDefault();
const { history } = this.context.router;
const { replace, to } = this.props;
if (replace) {
history.replace(to);
} else {
history.push(to);
}
}
};
複製代碼
同時下列四個條件時就會阻止默認行爲react-router
!event.defaultPrevented && event.button === 0 && !this.props.target && !isModifiedEvent(event)
複製代碼
react-router中除了Link還有一個NavLink,NavLink是一種特殊的Link,它的特殊體如今當與url匹配時生成的<a>標籤上會帶有一些樣式信息(經過activeClassName和activeStyle定義樣式)。函數
<NavLink
to="/faq"
activeClassName="selected"
>FAQs</NavLink>
<NavLink
to="/faq"
activeStyle={{
fontWeight: 'bold',
color: 'red'
}}
>FAQs</NavLink>
複製代碼
NavLink的特性須要作url的匹配查詢,以前在講路徑匹配的時候講到Route就是負責用來匹配路徑渲染組件的,所以這裏正適合引入Route來作匹配。匹配成功渲染帶樣式的Link,匹配失敗則渲染不帶樣式的Link。post
Route定義路徑關聯組件的方式有三種:ui
render與component方式定義的組件當不匹配時是不會渲染組件的this
children方式則只是將匹配規則傳入進來,具體是否渲染由children本身定義。children的這個特性恰好符合知足NavLink的要求。
明白了NavLink的大致思路後能夠去看看源碼的具體實現。
render() {
return (
<Route
path={escapedPath}
exact={exact}
strict={strict}
location={location}
children={({ location, match }) => {
const isActive = !!(getIsActive ? getIsActive(match, location) : match);
return (
<Link
to={to}
className={
isActive
? [className, activeClassName].filter(i => i).join(" ")
: className
}
style={isActive ? { ...style, ...activeStyle } : style}
aria-current={(isActive && ariaCurrent) || null}
{...rest}
/>
);
}}
/>
);
}
複製代碼