发表于:2014-09-20express
本文已过期,推荐阅读最新的 React Router v0.13.3 版使用指南api
本文已过期,推荐阅读最新的 React Router v0.13.3 版使用指南浏览器
本文已过期,推荐阅读最新的 React Router v0.13.3 版使用指南react-router
在构建一个复杂的页面时,给不一样的操做赋予不一样的路由(route)是一个很好的实践。对于习惯Backbone的人来讲Backbone.Router
就是一个很方便的route-action
映射模块,那么在React中应该怎样增长路由呢?虽然也可使用Backbone的解决方案,可是ReactRouter或许是一个更符合React思想的路由组件。ide
ReactRouter(github地址)是由Ryan Florence开发的应用于ReactJS的路由组件,它经过定义ReactJS组件<Routes>
及相关子组件来实现页面路由的映射、参数的解析和传递。若是你熟悉ember.js
,你会发现它处理路由的方式和ember的思想是一致的。函数
一个最基本的页面,菜单有「图书」和「电影」两个选项,点击「图书」显示图书列表(连接变为/books),点击「电影」显示电影列表(连接变为/movies)。
var ReactRouter = require('react-router'); var Routes = ReactRouter.Routes; var Route = ReactRouter.Route; //定义整个页面的路由结构 var routes = ( <Routes location="hash"> <Route path="/" handler={App}> <Route path="books" name="bookList" handler={Books}/> <Route path="movies" name="movieList" handler={Movies}/> </Route> </Routes>);
这样就定义了包含两条路由规则的路由,一条指向 /books,一条指向 /movies。(严格来讲应该是三条路由,还有一个指向 / 的路由)
<Routes>
组件接受一个名为 location 的 props,这是用来定义用何种前端技术实现路由,可选参数为hash或histroy。hash表示经过改变location.hash更新页面连接,而histroy表示使用history.pushState来更新连接。若是不考虑兼容IE8,能够选择history。
<Route>
组件是ReactRouter的核心组件,经过它来定义路由对应的路径,处理这条路由的组件(handler)等等。其中path属性是指这条路由对应的路径,好比
<Route path="books" name="bookList" handler="Books"/>
点击后浏览器中的路径就会变为 http://你的网址/#/books
。
而handler是指当这条路由被触发时该渲染哪一个组件,其中Books
就是一个React组件。之因此把 name 放在最后讲,是由于 name 是用在使用路由的时候起做用。
上面咱们定义了整个页面的路由规则,但总须要点击一个什么连接才能触发这个路由吧,下面咱们就来加上这么一个触发器
,同时看看 name 什么用。
//在上述代码的基础上 var Link = ReactRouter.Link; var App = React.createClass({ render: function(){ return ( <div className="main"> <nav> <Link to="bookList">图书</Link> <Link to="moviewList">电影</Link> </nav> <div className="content"> <this.props.activeRouteHandler/> </div> </div> ); } }; //routes在上述代码中已定义 React.renderComponent(routes, document.body);
在上述代码中咱们新require了一个React组件Link
,这就是咱们路由的触发器
,你能够把它理解为高级版的<a href="#你的hash">连接文字</a>
。注意咱们定义的Link
中有一个 to 属性,这就是对应了以前定义的路由中<Route>
组件的 name 属性。好比
<Link to="bookList">图书</Link>
点击后就会触发
<Route path="books" name="bookList" handler="Books"/>
从而致使Books
这个React组件被渲染。ReactRouter还作了一个很贴心的功能,当点击Link触发对应的路由后,Link
自己还会被添加 active 的className,方便你对当前激活的菜单项添加样式。(效果见DEMO,className默认是 active,能够经过传 props 改变)
问题又来了,哪一行代码定义了该渲染哪一个组件呢?注意咱们的 App
组件中的<this.props.activeRouteHandler/>
,这就是ReactRouter为咱们自动添加的当前 active 的handler,当点击 bookList
时,activeRouteHandler就是Books组件。
另外还须要注意一点,和咱们习惯中的React渲染方式不一样,最终渲染到DOM上的组件并非常规的React组件,而是咱们定义的routes
。注意React.renderComponent(routes, document.body);
这一行。
把玩一下DEMO你会发现,虽然路由起做用了(因为jsfiddle沙盒的限制,路由的改变并无反映到浏览器的地址栏中),可是在默认状态下除了两个菜单项啥都没有渲染,这和咱们的预期不符。
若是你想默认就显示全部图书,即默认渲染Books
这个React组件,那么你须要引入一个新的ReactRouter组件Redirect
。
var Redirect = ReactRouter.Redirect; var routes = ( <Routes location="hash"> <Route path="/" handler={App}> <Route path="books" name="bookList" handler={Books}/> <Route path="movies" name="movieList" handler={Movies}/> <Redirect to="bookList"/> </Route> </Routes>);
和Link
相似,Redirect
也有 to 属性,这个属性定义了重定向的地址。咱们的routes
更新后,当访问当前页面时(即访问 / 时),会自动跳转到 /books。
若是你不想默认显示图书或电影,而是另外一个组件,好比欢迎信息什么的,可使用DefaultRoute
。
var DefaultRoute = ReactRouter.DefaultRoute; var routes = ( <Routes location="hash"> <Route path="/" handler={App}> <Route path="books" name="bookList" handler={Books}/> <Route path="movies" name="movieList" handler={Movies}/> <DefaultRoute handler={Welcome}/> </Route> </Routes>);
这样在访问 / 时,默认会渲染Welcome
组件,注意这个时候两个菜单项都没有被激活(即没有 active 的className),除非你点击「图书」或「电影」。
业务逻辑更复杂了,如今除了点击「图书」显示图书列表,点击「电影」显示电影列表外,点击某一本图书(或某一部电影)还要显示对应的详情。
首先更新路由对象
var routes = ( <Routes location="hash"> <Route path="/" handler={App}> <Route path="books" name="bookList" handler={Books}> <Route path=":bookId" name="book" handler={Book}/> </Route> <Route path="movies" name="movieList" handler={Movies}> <Route path=":movieId" name="movie" handler={Movie}/> </Route> <DefaultRoute handler={Welcome}/> </Route> </Routes>);
和以前的路由对象相似,须要嵌套的路由直接进行嵌套便可(彻底就是字面意思嘛),可是注意到咱们的<Route>
的path变成了一个奇怪的形式,「:bookId」和「:movieId」是什么意思?熟悉express
的同窗应该对这样的路由形式不会陌生,这定义了路由接受的一个参数,简单的说 /moview/:movieId 定义了一个规则,当访问 /moviews/123 的时候,程序会自动把 123 提取出来当作名为 movieId 的参数。
详细的介绍见路由匹配规则。
既然咱们的路由更新了,那么对应的 handler 也应该进行更新。首先给Books
和Movies
这两个组件在render时添加<this.props.activeRouteHandler/>
,而后再新建显示单个图书和单个电影的React组件Book
及Movie
。
注意在渲染单个图书或电影的组件中,咱们能够经过this.props.params
来提取经过路由传进来的参数(效果见DEMO)。
另外还要注意一点,正如你在DEMO中看到的,嵌套的路由对应的Link
对象(即视觉上的菜单项)会所有被添加 active 的className,当你查看某一本书的详情时,书名及图书菜单都处于高亮状态,一条龙高亮。
这里还有另一个问题,若是咱们想点击某本书的时候再也不显示图书列表而是只显示菜单和图书详情该怎么办呢?咱们再对路由对象进行小小的改动。
var routes = ( <Routes location="hash"> <Route path="/" handler={App}> <Route path="books" name="bookList" handler={BookRoute}> <Route path=":bookId" name="book" handler={Book}/> <DefaultRoute handler={Books}/> </Route> <Route path="movies" name="movieList" handler={MovieRoute}> <Route path=":movieId" name="movie" handler={Movie}/> <DefaultRoute handler={Movies}/> </Route> <DefaultRoute handler={Welcome}/> </Route> </Routes>);
首先咱们修改了本来显示图书列表及电影列表的handler,将它们改成新的React组件BookRoute
及MovieRoute
,这两个组件的功能就是渲染 this.props.activeHandler
。
其次咱们将本来的列表当作<DefaultRoute>
渲染,这样就能实现点击单条信息的时候再也不显示列表了。不过这样就须要新增长两个傀儡handler,不知道你们有没有更好的办法实现。
以上基本覆盖了SPA中对于路由使用的大多数use case,除了上述功能外,ReactRouter还提供了用于获取当前active路由的mixin ActiveState
,以及其它实用的工具函数及方法,具体请参考其 API 文档。
最后还有个小内幕,React的核心做者之一也参与了ReactRouter的开发,所以看来ReactRouter仍是颇有潜力的!
本文已过期,推荐阅读最新的 React Router v0.13.3 版使用指南
本文已过期,推荐阅读最新的 React Router v0.13.3 版使用指南
本文已过期,推荐阅读最新的 React Router v0.13.3 版使用指南
© 2014 undefined
Powered by Ghost
Theme by undefinedblog