谈谈
近来运用的 React + webpack 来开辟项目,觉得确实是爽的飞起,然则总觉得照样少了点什么。
对,是多页面,每次要求页面还要后端路由给你?多不爽啊,尝尝 react-router ,几乎掌控一切的觉得,只开放一个页面路由接口,其他全给数据接口就了,能够和后端哥哥说拜拜了。
??????????? 啪啪啪啪啪~
概述
先贴上官方文档 https://github.com/rackt/react-router/tree/master/docs.
对了这里另有一份中文文档(不过不是很全)http://react-guide.github.io/react-router-cn/.
react-router 是 React 的完全前端路由处置惩罚方案,迥殊在做一个 spa 运用的时刻,他能完成 url 和 视图ui 的同步,而且支撑后端衬着,异步按需加载等等。
由于 react-router 文档的多变,这里的例子以当前版本 1.0.1 为准。(1.0之前文档每个版本的更改都很大,索多了都是泪)
浏览器支撑
一切支撑 React 的浏览器。
发起!发起人人也挽劝身旁的人用现代化浏览器,关爱前端开辟者。
装置
npm install react-router@latest
同时,react-router 是基于 history 开辟的,这里你须要装置 history。
注重 react-router 当前版本 1.0.1 依靠的是 history 1.13.1 请不要装置最新版。
不要问我为何晓得,被坑惨了;有同学问,那没有办法用 history 的最新版本嘛?毕竟这只是暂缓之计,处置惩罚方案照样有的,那就是等 react-router 作者处置惩罚咯 ?。
npm install history@1.13.1
构建东西的话,我依旧发起是 webpack , React 和 webpack 是一对好兄弟。
npm install webpack
webpack的运用要领能够看我的前两篇文章:
小例子
// 加载依靠包,这是 es6 的语法(我好烦琐)。
import React from 'react'
import { render } from 'react-dom'
// 这里从 react-router 引入了三个组件,先不诠释。
import { Router, Route, Link } from 'react-router'
const App = React.createClass({
render() {
return (
<div>
<h1>App</h1>
<ul>
<li><Link to="/about">About</Link></li>
<li><Link to="/inbox">Inbox</Link></li>
</ul>
{this.props.children}
</div>
)
}
});
const Inbox = React.createClass({
render() {
return (
<div>
Inbox
</div>
)
}
});
const About = React.createClass({
render() {
return (
<div>
About
</div>
)
}
});
render((
<Router>
<Route path="/" component={App}>
<Route path="about" component={About} />
<Route path="inbox" component={Inbox} />
</Route>
</Router>
), document.getElementById('root'));
我就偷个懒把官方文档的demo直接copy了。
直接先来看 render 下面的内容,这里是用 jsx 语法。 最外层组件是 Router(能够把他看做是react-router供应的最外层容器) , 下一层是 Route,这个是路由组件。对应关联以下:/ ---> <App />
/about ---> <App><About /></App>
/inbox ---> <App><Inbox /></App>
path 对应途径,component 对应当前途径衬着的组件。
Route 内里的 Route 示意在父组件路由的 path 途径下面的一级 path 对应的路由,这里的路由是父子嵌套,对应的组件也一样是父子嵌套的。
假如是多级嵌套也一样云云。
不想用 jsx 来写,换个体式格局吧~
以上例子能够改写成:
...
const routerConfig = [
{
path: '/',
component: App,
childrenRoutes: [
{ path: 'about', component: About },
{ path: 'inbox', component: Inbox },
]
}
];
render((
<Router routes={routeConfig} />
), document.getElementById('root'));
这里的构造就更清楚了,我是比较喜好这类体式格局。
默许的路由
比方上面的例子,/ 关于的组件是 App , 假如 App 只是衬着了一个导航条,却没有自组件,那翻开 比方 qiutc.me/ 的时刻不是就没有内容了吗。
把上面例子改一下
...
// 增加组件 Index
const Index = React.createClass({
render() {
return (
<div>
Index
Index
Index
</div>
)
}
});
// 修正设置
const routerConfig = [
{
path: '/',
component: App,
indexRoute: { component: Index },
childrenRoutes: [
{ path: 'about', component: About },
{ path: 'inbox', component: Inbox },
]
}
];
这里加了一个 indexRoute
,示意他在没有婚配子路由的时刻,在 / 路由下衬着默许的子组件 Index。
路由组件嵌套也是一样的,比方:
{ path: 'about', component: About, indexRoute: {component: AboutIndex} },
以此类推。
404 NotFound
假如我们翻开了一个没有设置路由的链接,就必定须要一个友爱的 404 页面。设置以下:
...
// 增加 404 组件
const NotFound = React.createClass({
render() {
return (
<div>
404
NotFound
</div>
)
}
});
// 修正设置
const routerConfig = [
{
path: '/',
component: App,
indexRoute: { component: Index },
childrenRoutes: [
{ path: 'about', component: About },
{ path: 'inbox', component: Inbox },
]
},
{
path: '*',
component: NotFound,
}
];
云云简朴。
绝对途径与重定向
const routerConfig = [
{
path: '/',
component: App,
indexRoute: { component: Index },
childrenRoutes: [
{ path: 'about', component: About },
{
path: 'inbox',
component: Inbox,
childrenRoutes: [
{
path: 'message/:id',
component: Message,
}
],
},
]
},
{
path: '*',
component: NotFound,
}
];
在这里我们接见 /inbox/message/1 关于衬着 Message 组件,这个链接太长了,我们想直接 /message/1 那怎么办,改路由构造?太麻烦了!绝对途径能够帮你做到这个。
把 path: 'message/:id',
改成 path: '/message/:id',
就好了。
等等假如用户之前珍藏的链接是 /inbox/message/1 ,那不是就打不开了嘛,和后端路由一样,react-router 也有重定向:redirect
const routerConfig = [
{
path: '/',
component: App,
indexRoute: { component: Index },
childrenRoutes: [
{ path: 'about', component: About },
{
path: 'inbox',
component: Inbox,
childrenRoutes: [
{
path: '/message/:id',
component: Message,
},
{
path: 'message/:id',
onEnter: function (nextState, replaceState) {
replaceState(null, '/messages/' + nextState.params.id);
}
}
],
},
]
},
{
path: '*',
component: NotFound,
}
];
onEnter 要领示意进入这个路由前实行的要领,在进入 /inbox/messages/:id 的前,实行
function (nextState, replaceState) {
replaceState(null, '/messages/' + nextState.params.id);
}
nextState
示意要进入的下一个路由,这里就是 /inbox/messages/:id ,replaceState
示意替代路由状况的要领,把 /inbox/messages/:id 替代成 /messages/:id,然后就能够重定向到 /messages/:id。
一样的也有 onLeave 这个要领
示意在脱离路由前实行。
———————————————————
固然假如你用的是 jsx 语法,有更简朴的组件能够完成:
import { Redirect } from 'react-router'
React.render((
<Router>
<Route path="/" component={App}>
<IndexRoute component={Index} />
<Route path="about" component={About} />
<Route path="inbox" component={Inbox}>
<Route path="/messages/:id" component={Message} />
{/* 跳转 /inbox/messages/:id 到 /messages/:id */}
<Redirect from="messages/:id" to="/messages/:id" />
</Route>
</Route>
</Router>
), document.getElementById('root'))
途径婚配道理
嵌套关联
React Router 运用路由嵌套的观点来让你定义 view 的嵌套鸠合,当一个给定的 URL 被调用时,全部鸠合中(掷中的部份)都邑被衬着。嵌套路由被形貌成一种树形构造。React Router 会深度优先遍历全部来由设置来寻觅一个与给定的 URL 相婚配的路由。
简朴来说,就是说,婚配的时刻会先婚配到外层途径,然后顺次遍历到内层。
比方 /inbox/messages/:id 会先婚配 /,衬着 / 对应的组件 App,然后再到 / 的下一层寻觅 /inbox ,一样衬着 /inbox 对应的组件 Inbox,顺次类推,直到到 message/:id。
tip:运用绝对途径能够疏忽嵌套关联,如上面例子。
途径语法
路由途径是婚配一个(或一部份)URL 的 一个字符串情势。大部份的路由途径都能够直接依据字面量明白,除了以下几个特别的标记:
/:paramName – 婚配一段位于 /、? 或 # 以后的 URL。 掷中的部份将被作为一个参数
(/) – 在它内部的内容被认为是可选的
/* – 婚配恣意字符(非贪欲的)直到掷中下一个字符或许全部 URL 的末端,并建立一个 splat 参数
<Route path="/hello/:name"> // 婚配 /hello/michael 和 /hello/ryan <Route path="/hello(/:name)"> // 婚配 /hello, /hello/michael 和 /hello/ryan <Route path="/files/*.*"> // 婚配 /files/hello.jpg 和 /files/path/to/hello.jpg
优先级
末了,路由算法会依据定义的递次自顶向下婚配路由。因而,当你具有两个兄弟路由节点设置时,你必需确认前一个路由不会婚配后一个路由中的途径。比方:
<Route path="/comments" ... />
<Redirect from="/comments" ... />
第二个是不会被实行的。
拿到参数途径的
比方上面的 /messages/:id ,这个id多是我们在 Message 猎取数据时须要的 id。
他会被当作一个参数传给 params,parmas 会传给 Message 组件的 props:
const Message = React.createClass({
render: function() {
return (
<div>{ this.props.params.id }</div>
);
}
});
如许就能够猎取到了。
history 设置
React Router 是建立在 history 之上的。 简而言之,一个 history 晓得怎样去监听浏览器地点栏的变化, 并剖析这个 URL 转化为 location 对象, 然后 router 运用它婚配到路由,末了正确地衬着对应的组件。
经常使用的 history 有三种情势, 然则你也能够运用 React Router 完成自定义的 history。
createHashHistory
createBrowserHistory
createMemoryHistory
这三个有什么区别呢:
createHashHistory
这是一个你会猎取到的默许 history ,假如你不指定某个 history 。它用到的是 URL 中的 hash(#)部份去建立形如 example.com/#/some/path 的路由。
这个 支撑 ie8+ 的浏览器,然则由于是 hash 值,所以不引荐运用。
createBrowserHistory
Browser history 是由 React Router 建立浏览器运用引荐的 history。它运用 History API 在浏览器中被建立用于处置惩罚 URL,新建一个像如许实在的 URL example.com/some/path。
Memoryhistory
不会在地点栏被操纵或读取。
运用
import { createBrowserHistory, useBasename } from 'history';
const historyConfig = useBasename(createHistory)({
basename: '/' // 根目录名
});
...
render((
<Router routes={routeConfig} History={historyConfig} />
), document.getElementById('root'));
Link&IndexLink
Link
我们在最开首看到如许一个东西:
const App = React.createClass({
render() {
return (
<div>
<h1>App</h1>
<ul>
<li><Link to="/about">About</Link></li>
<li><Link to="/inbox">Inbox</Link></li>
</ul>
{this.props.children}
</div>
)
}
});
Link 会被衬着成 a ,to 实在就是 href ,
然则 react-router 会阻挠默许跳转页面,而改成 history 路由的变更。
参数:
to
切换到的路由地点query
跟在 url 的 query 参数,比方
query={{q: "que"}} 对应 `/example?a=que
这里的 query 一样能够像 params 会被传入下一个路由组件的 props
hash
跟在 url 的 hash 参数,比方
hash={111} 对应 `/example#111
这里的 query 一样能够像 params 会被传入下一个路由组件的 props
activeClassName
当前 url 途径假如和 Link 的 to 婚配 这个 Link 就会有一个定义的属性,比方:
在 /index 下
<Link to="/index" activeClassName={"active"} activeStyle={{color: 'red'}} >/</Link>
这里衬着出来的 a 标签会有一个激活的 active 类名,还会有一个色彩 red
<Link to="/about" activeClassName={"active"} activeStyle={{color: 'red'}} >/</Link>
这里衬着出来的 a 标签就不会有以上属性
activeStyle
同上onClick
点击的时刻实行的函数,会传入一个 e 事宜对象,你能够e.stopPropagation()
阻挠默许路由切换。
IndexLink
在上面有一个题目假如:
在 / 下 和 /index
<Link to="/" activeClassName={"active"} activeStyle={{color: 'red'}} >/</Link>
这个 Link 衬着出来的 a 标签都邑激活 active 属性,而且会带上 color: 'red'
由于 / 和 /index 和 / 都是婚配的
这时刻就能够用:
<IndexLink to="/" activeClassName={"active"} activeStyle={{color: 'red'}} >/</IndexLink>
只会在 / 下呗激活,在 /index 或许其他下面,不会被激活
未完待续
关于 依据路由按需异步加载js 和 服务器端衬着路由视图 以及 react-router的更高等用法 会在下一篇文章来讨论。
毕竟哥也须要去深切研究一下才敢献丑。
?