React routerV4 笔记
一、基础路由示例
import React from 'react'
import {
BrowserRouter as Router,
Route,
Link
} from 'react-router-dom'
//1、写路由链接可以使用Link或者NavLink
const BasicExample = () => (
<Router>
<div>
<ul>
<li><Link to="/">首页</Link></li>
<li><Link to="/about">关于</Link></li>
<li><Link to="/topics">主题列表</Link></li>
</ul>
<hr/>
//2、配置路由路径
<Route exact path="/" component={Home}/>
<Route path="/about" component={About}/>
<Route path="/topics" component={Topics}/>
</div>
</Router>
)
//3、书写组件模块
const Home = () => (
<div>
<h2>首页</h2>
</div>
)
const About = () => (
<div>
<h2>关于</h2>
</div>
)
//特殊的组件,使用match参数传参,传递当前的url的值。还有个路由嵌套。
const Topics = ({ match }) => (
<div>
<h2>主题列表</h2>
<ul>
<li>
<Link to={`${match.url}/rendering`}>
使用 React 渲染
</Link>
</li>
<li>
<Link to={`${match.url}/components`}>
组件
</Link>
</li>
<li>
<Link to={`${match.url}/props-v-state`}>
属性 v. 状态
</Link>
</li>
</ul>
<Route path={`${match.url}/:topicId`} component={Topic}/>
<Route exact path={match.url} render={() => (
<h3>请选择一个主题。</h3>
)}/>
</div>
)
const Topic = ({ match }) => (
<div>
<h3>{match.params.topicId}</h3>
</div>
)
export default BasicExample
二、路由API总结
背景知识window.history新的Api
HTML5的新API扩展了window.history,使历史记录点更加开放了。可以存储当前历史记录点、替换当前历史记录点、监听历史记录点,下面逐一简要说明一下。
1、存储当前历史记录点
存储的方式类似于数组的入栈(Array.push()),在window.history里新增一个历史记录点,例如:
// 当前的url为:http://www.qingdou.me/index.html
var json={time:new Date().getTime()};
// @状态对象:记录历史记录点的额外对象,可以为空
// @页面标题:目前所有浏览器都不支持
// @可选的url:浏览器不会检查url是否存在,只改变url,url必须同域,不能跨域
window.history.pushState(json,”",”http://www.qingdou.me/post-1.html”);
var state = { title: title, url: options.url, otherkey: othervalue }; window.history.pushState(state, document.title, url);
history.pushState方法接受三个参数,依次为:
state:一个与指定网址相关的状态对象,popstate事件触发时,该对象会传入回调函数。如果不需要这个对象,此处可以填null。
title:新页面的标题,但是所有浏览器目前都忽略这个值,因此这里可以填null。
url:新的网址,必须与当前页面处在同一个域。浏览器的地址栏将显示这个网址。
执行了pushState方法后,页面的url地址为http://www.qingdou.me/post-1.html。
2、替换当前历史记录点
window.history.replaceState和window.history.pushState类似,不同之处在于replaceState不会在window.history里新增历史记录点,其效果类似于window.location.replace(url),都是不会在历史记录点里新增一个记录点的。当你为了响应用户的某些操作,而要更新当前历史记录条目的状态对象或URL时,使用replaceState()方法会特别合适。
3、监听历史记录点
监听历史记录点,直观的可认为是监听URL的变化,但会忽略URL的hash部分,监听URL的hash部分,HTML5有新的API为onhashchange,我的博客里也有说到该方法和跨浏览器的兼容解决方案。可以通过window.onpopstate来监听url的变化,并且可以获取存储在该历史记录点的状态对象,也就是上文说到的json对象,如:
// 当前的url为:http://www.qingdou.me/post-1.html
window.onpopstate=function()
{
// 获得存储在该历史记录点的json对象
var json=window.history.state;
// 点击一次回退到:http://www.qingdou.me/index.html
// 获得的json为null
// 再点击一次前进到:http://www.qingdou.me/post-1.html
// 获得json为{time:1369647895656}
}
值得注意的是:javascript脚本执行window.history.pushState和window.history.replaceState不会触发onpopstate事件。
还有一点注意的是,谷歌浏览器和火狐浏览器在页面第一次打开的反应是不同的,谷歌浏览器奇怪的是回触发onpopstate事件,而火狐浏览器则不会。
浏览器兼容性表:
Feature
|
Chrome
|
Firefox (Gecko)
|
Internet Explorer
|
Opera
|
Safari
|
replaceState, pushState
|
5
|
4.0 (2.0)
|
10
|
11.50
|
5.0
|
history.state
|
18
|
4.0 (2.0)
|
10
|
11.50
|
6.0
|
基于ajax与html无刷新换url的jquery插件pjax。
Router的API
1、<BrowserRouter>
使用 HTML5 历史 API 记录( pushState,replaceState 和 popstate 事件)的 <Router> 使你的UI与URL保持同步。
属性:
basename: string
所有地址的基本网址。如果您的应用程序是从服务器上的子目录提供的,则需要将其设置为子目录。格式正确的基本名应该有一个前导斜线,但是结尾不能有斜线。
<BrowserRouter basename="/calendar"/> <Link to="/today"/> // renders <a href="/calendar/today">
forceRefresh: bool
如果为 true,则路由器将在页面导航中使用整页刷新。
getUserConfirmation: func
当导航需要确认时执行的函数。默认使用 window.confirm
// 使用默认的确认函数 const getConfirmation = (message, callback) => { const allowTransition = window.confirm(message) callback(allowTransition) } <BrowserRouter getUserConfirmation={getConfirmation}/>
forceRefresh: bool
当设置为 true 时,在导航的过程中整个页面将会刷新。 只有当浏览器不支持 HTML5 的 history API 时,才设置为 true
const supportsHistory = 'pushState' in window.history <BrowserRouter forceRefresh={!supportsHistory}/>
2、<HashRouter>
HashRouter 是一种特定的 <Router>, HashRouter 使用 URL 的 hash (例如:window.location.hash) 来保持 UI 和 URL 的同步。
注意: 使用 hash 的方式记录导航历史不支持 location.key 和 location.state。 在以前的版本中,我们为这种行为提供了 shim,但是仍有一些问题我们无法解决。 任何依赖此行为的代码或插件都将无法正常使用。 由于该技术仅用于支持传统的浏览器,因此在用于浏览器时可以使用 <BrowserHistory> 代替。
hashRouter和browserRouter属性类似。唯一不同的多一个
hashType: string
window.location.hash 使用的 hash 类型。有如下几种:
- "slash" - 后面跟一个斜杠,例如 #/ 和 #/sunshine/lollipops
- "noslash" - 后面没有斜杠,例如 # 和 #sunshine/lollipops
- "hashbang" - Google 风格的 “ajax crawlable”,例如 #!/ 和 #!/sunshine/lollipops
默认为 "slash"。
3、Link
属性:
1、to后可以为string或者object均可
2、replace: bool
当设置为 true 时,点击链接后将使用新地址替换掉访问历史记录里面的原地址。
当设置为 false 时,点击链接后将在原有访问历史记录的基础上添加一个新的纪录。
默认为 false。
4、NavLink
当它与当前 URL 匹配时,为其渲染元素添加样式属性。
NavLink和Link类似,只是多几个属性。关键是可以使用activeClassName(string)属性和activeStyle(object)属性
exact: bool
如果为 true,则仅在位置完全匹配时才应用 active 的类/样式。
strict: bool
当情况为 true,要考虑位置是否匹配当前的URL时,pathname 尾部的斜线要考虑在内。有关更多信息,请参见 <Route strict> 文档。
isActive: func
一个为了确定链接是否处于活动状态而添加额外逻辑的函数,如果你想做的不仅仅是验证链接的路径名与当前 URL 的 pathname 是否匹配,那么应该使用它
5、<Prompt/>
用于在用户离开页面之前及时提示用户。当你的应用程序进入应阻止用户离开的状态时(比如一个表格被填满了一半),渲染一个 <Prompt> 。
它有两个属性:1、message:string 用户试图离开时的提示信息。 message:function 将用户试图前往到的下一个 Location 和 action 调用。返回一个字符串以向用户显示提示符,或返回 true 以允许转换。
<Prompt message={location => ( location.pathname.startsWith('/app') ? true : `Are you sure you want to go to ${location.pathname}?` )}/>
2、when 你可以一直渲染而不是在警示框出现之后才渲染一个 <Prompt> ,但是可以通过 when={true} 或 when={false} 来阻止或允许相应的导航。
6、<Redirect>
使用Redirect组件将导航到一个新的地址。这个新地址会覆盖history栈中的当前地址。
属性:to: string、to: object to属性即重定向到的url。
push: bool 当true时,重定向会将新地址推入history中,而不是替换当前地址。
from: string 设置从哪个路径重定向到to的路径。
exact: bool 完全匹配from
strict: bool 严格匹配from
7、<Route>
Route 组件也许是 React Router 中最重要的组件,它可以让你理解并学习如何使用它。它最基本的职责是在 location 与 Route 的 path 匹配时呈现一些 UI。
Route render methods
<Route>有三种渲染方法:
<Route component> 只有当位置匹配时才会渲染的React组件。
<Route render> func 方便内联渲染和包裹。
<Route children> func 不论路径是否匹配,均会渲染此函数。
属性:
path: string 路径
exact: bool 如果为true只有在路径完全匹配时才渲染
strict: bool
eg: 如果为 true 当真实的路径具有一个斜线将只匹配一个斜线location.pathname,如果有更多的URL段 location.pathname ,将不起作用
<Route strict path="/one/" component={About}/>
path
|
location.pathname
|
matches?
|
/one/
|
/one
|
no
|
/one/
|
/one/
|
yes
|
/one/
|
/one/two
|
yes
|
**警告:**可以使用 strict 来强制执行 location.pathname 没有结尾斜杠,但为了执行此操作,strict 和 exact 必须都是 true 。
<Route exact strict path="/one" component={About}/>
path
|
location.pathname
|
matches?
|
/one
|
/one
|
yes
|
/one
|
/one/
|
no
|
/one
|
/one/two
|
no
|
sensitive: bool
如果路径区分大小写,则为 true ,则匹配。
<Route sensitive path="/one" component={About}/>
path
|
location.pathname
|
sensitive
|
matches?
|
/one
|
/one
|
true
|
yes
|
/One
|
/one
|
true
|
no
|
/One
|
/one
|
false
|
yes
|
所有三种渲染方法都将通过相同的三个 Route 属性。
match
1、一个 match 对象中包涵了有关如何匹配 URL 的信息。match 对象中包涵以下属性:
params - (object) key/value 与动态路径的 URL 对应解析
isExact - (boolean) true 如果匹配整个 URL (没有结尾字符)
path - (string) 用于匹配的路径模式。被嵌套在 <Route> 中使用
url - (string) 用于匹配部分的 URL 。被嵌套在 <Link> 中使用
你将会在这些地方用到 match 对象:
- Route component 例如 this.props.match
- Route render 例如 ({ match }) => ()
- Route children 例如 ({ match }) => ()
- withRouter 例如 this.props.match
- matchPath 例如 返回值
如果 Route 没有 path,那么将会一直与他最近的父级匹配。这也同样适用于withRouter。
null matches
当前路由的 path 与当前地址不匹配时,使用 children 属性的 <Route> 将调用 children 方法。这种情况下, match 将为 null 。当<Route> 中的内容能够被渲染出来时,说明匹配成功,但这种情况是有挑战性的。
“解析”URL的默认方式是将 match.url 字符串连接到“相对”路径。
`${match.url}/relative-path`
如果你的匹配为 null 时尝试执行此操作,则会出现TypeError。它的意思是在使用子级属性时在 <Route> 内部加入“相对”路径是不安全的。
当您在生成null匹配对象的 <Route> 内部使用无路径的 <Route> 时。会出现类似但更微妙的情况。
// location.pathname = '/matches' <Route path='/does-not-match' children={({ match }) => ( // match === null <Route render={({ match:pathlessMatch }) => ( // pathlessMatch === ??? )}/> )}/>
无路径的 <Route> 从它们的父节点继承它们的match对象。 如果他们的父match是null,那么他们的匹配也是null。
这意味着:a)任何子路由/链接必须是绝对的,因为没有父级去解决,
并且b)父级路径match可以是null的无路径路由将需要使用子级属性进行渲染
location
location 代表应用程序现在在哪,你想让它去哪,或者甚至它曾经在哪。
router 将在这几个地方为您提供一个 location 对象:
- Route component as this.props.location
- Route render as ({ location }) => ()
- Route children as ({ location }) => ()
- withRouter as this.props.location
它也可以在 history.location 找到,但是你不应该使用它,因为它是可变的,你可以在 history 文档中阅读更多内容。
location 对象永远不会发生变化,因此你可以在生命周期钩子中使用它来确定何时导航,这对数据抓取和动画非常有用。
history
“history” 以及 “history对象”指的是 history 包中的内容,该包是 React Router 仅有的两大主要依赖之一(除去 React 本身),在不同的 Javascript 环境中,它提供多种不同的形式来实现对 session 历史的管理。
我们也会使用以下术语:
- “browser history” - 在特定 DOM 上的实现,使用于支持 HTML5 history API 的 web 浏览器中
- “hash history” - 在特定 DOM 上的实现,使用于旧版本的 web 浏览器中
- “memory history” - 在内存中的 history 实现,使用于测试或者非 DOM 环境中,例如 React Native
history 对象通常会具有以下属性和方法:
- length - (number 类型) history 堆栈的条目数
- action - (string 类型) 当前的操作(PUSH, REPLACE, POP)
- location - (object 类型) 当前的位置。location 会具有以下属性:
- pathname - (string 类型) URL 路径
- search - (string 类型) URL 中的查询字符串
- hash - (string 类型) URL 的哈希片段
- state - (object 类型) 提供给例如使用 push(path, state) 操作将 location 放入堆栈时的特定 location 状态。只在浏览器和内存历史中可用。
- push(path, [state]) - (function 类型) 在 history 堆栈添加一个新条目
- replace(path, [state]) - (function 类型) 替换在 history 堆栈中的当前条目
- go(n) - (function 类型) 将 history 堆栈中的指针调整 n
- goBack() - (function 类型) 等同于 go(-1)
- goForward() - (function 类型) 等同于 go(1)
- block(prompt) - (function 类型) 阻止跳转。(详见 history 文档)。
history 是可变的
history 对象是可变的,因此我们建议从 <Route> 的渲染选项中来访问 location,而不是从 history.location 直接获取。
8、Switch
渲染与该地址匹配的第一个子节点<Route>或者<Redirect>
<Switch> <Route exact path="/" component={Home}/> <Route path="/about" component={About}/> <Route path="/:user" component={User}/> <Route component={NoMatch}/> </Switch>
如果为 <Switch> 提供了 location 属性,它将覆盖匹配子元素上的 location属性。
9、withRouter
您可以通过 withRouter 高阶组件访问 history 对象的属性和最近的 <Route>的 match 。 当路由渲染时, withRouter 会将已经更新的 match , location和 history 属性传递给被包裹的组件。
const AuthButton = withRouter(({ history }) => (
fakeAuth.isAuthenticated ? (
<p>
Welcome! <button onClick={() => {
fakeAuth.signout(() => history.push('/'))
}}>Sign out</button>
</p>
) : (
<p>You are not logged in.</p>
)
))
10、<Router>
Router 是所有路由组件共用的底层接口。通常,我们的应用程序将使用其中一个高级路由器代替:
- <BrowserRouter>
- <HashRouter>
- <MemoryRouter>
- <NativeRouter>
- <StaticRouter>