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}
/>
);
}}
/>
);
}
复制代码