使用 React-Router 创建单页应用
最近业余时间在学习 React,配合 Redux 和 React-Router 正在不紧不慢地开发一个小工具moviemaster,用于管理硬盘中的电影剧集。在单页应用开发中,redux 并不是必须的,所以今天只讲讲 前端的路由系统以及 React-Router的简单使用。 什么是路由以下来自维基百科::
这是网络工程中的术语,对大家而言,最熟悉的应该就是家里的路由器。路由是指路由器从一个接口上收到数据包,根据数据包的目的地址进行定向并转发到另一个接口的过程。放在 Web 上来说,url 就像是路由器中的路由表,每个 url 对应不同的页面或者内容,就像路由表中的的 IP 对应不同的网络一样。 先来看一下熟悉的套路:
在传统的网页应用架构中,客户端只是一个展示层,通过 url 访问服务端,服务端则根据自己的“路由表”将对应的页面分发给客户端。但是在这种模式下,ajax 异步加载的内容是无法通过url 记录的。无论你在页面上操作了多少,异步请求了多少数据,在每次重新访问同一个 url 时,服务端返回给客户端的内容都是一模一样。
如果前端有自己专属的“路由表”来分发页面上不同的状态,那不就行了? Hash 和 pushState据我所知,目前有两种方式可以构建出前端的路由系统:url 中的#和 HTML5中的 history API。其原理如下:
经典的 Hash#代表网页中的一个位置。后面接着的字符,就是该位置的标识符。比如, https://zhanglun.github.io/index.html#body 就代表网页 index.html 的 body 位置。浏览器读取这个 URL 后,会自动将body位置滚动至可视区域。标识符的指定有两个方法。
<a name="body"></a>
<div id="body" > #是用来指向文档的内容,属于浏览器的行为,与服务端无关,在 HTTP请求中也不会携带 #及其后面的内容,对于服务端而言 http://www.baidu.com 和 http://www.baidu.com#action=fuckbaidu 返回给客户端的都是前者所分发的内容,但是在浏览器中可以通过 Window 对象上的 比如: http://www.example.com/ http://www.examplt.com/#edit http://www.examplt.com/#settings
以下是伪代码: function hashHandler () { let key = location.hash.slice(1); switch(key) { case 'edit': renderEditPanel(); break; case 'settings': renderSettings(); break; default: break; } } window.onload = () => { hashHandler(); } window.onhashchange = () => { hashHandler(); } HTML5 中的 pushStatepushState是 History API中的一个方法,其文档可以看这里 MDN History。它的功能简单的说就是:修改 url,添加历史记录。比如 我的做法是:对应的url 返回的都是同一个页面,然后浏览器接受之后检查前端定义路由系统,执行响应的代码。这个方法可能会造成页面平白添加一个短暂的延迟,不过影响不是很大。 React-Router的使用目前来说,任何一个路由系统库或者框架,虽说是写法不一,但是都是在上述两种方式的基础上实现的。让我觉得耳目一新的是:使用路由嵌套的概念来定义 view 的嵌套集合,当一个给定的 URL 被调用时,整个集合中(命中的部分)都会被渲染。 import React from 'react'; import { render } from 'react-dom'; import { Router,Route,IndexRoute,hashHistory } from 'react-router'; import App from './containers/App'; import MovieContainer from './containers/Movies'; import Detail from './containers/Detail'; let rootElement = document.getElementById('app'); render( <Router> <Route path="/" component={App}> <Route path="about" component={About} /> <Route path="inbox" component={Inbox}> <Route path="messages/:id" component={Message} /> </Route> </Route> </Router>,rootElement); 在入口文件中,引入 React-Router,以组件的形式在 render 中使用,上述代码配置结果如下:
在路由中,组件对应设置的子组件可以通过 class App extend Component { constructor(props) { super(props) } render() { <div id="app"> <h1>Hello,world!</h1> {this.props.children} </div> } } 当 URL 为 / 时, App 中并没有渲染任何的组件,render 中的 this.props.children 还是 undefined。此时可以使用 render( <Router> <Route path="/" component={App}> {/* 当 url 为/时渲染 Welcome */} <IndexRoute component={Welcome} /> <Route path="about" component={About} /> <Route path="inbox" component={Inbox}> <Route path="messages/:id" component={Message} /> </Route> </Route> </Router>,rootElement);
看一下这一段代码 <Route path="posts" component={Post}> <Route path="users/:userid" component={User}> <Route path="messages/:messageid" component={Message} /> </Route> </Route> 此时匹配的路由分别是: <Route path="posts" component={Inbox}> <Route path="/users/:userid" component={Message}> <Route path="/messages/:messageid" component={Message} /> </Route> </Route>
基础的配置完成之后,通过 (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |