模块开发之react-router使用(八)
前言
路由其实决定了链接跳转到哪个界面。
比如http://localhost:8080/app/list
,正常情况下链接发送到后端,由后端决定返回的页面,但由于现在前端技术的发展,模块化开发,前端可以自己决定返回的页面内容,这就是本文需要解释的路由
的概念。即路由
决定跳转到哪个界面。
路由是用来区分一个网站不同功能模块的地址,浏览器通过访问同一站点下的不同路由,来访问网站不同的功能。同样路由也让开发者区分返回的内容。
·React-router是一个非常好有的路由插件,它从整体上管理整个应用上的路由跳转。
本文件使用ES6模块加载方式,不是CommonJS,CMD,AMD模块规范。React-Router4由3部分组件,react-router
,react-router-dom
和react-router-native
。其中react-router
是核心模块,集合react-router-dom
和react-router-native
功能在一起,网络开发只要引入react-router-dom
即可,他已经暴露了react-router
核心模块里接口
引入模块
EC6引入模块方式
import { HashRouter as Router, Route, Switch, Redirect } from 'react-router-dom'
或
import { BrowserRouter as Router, Route, Switch, Redirect } from 'react-router-dom'
2种方式只有HashRouter as Router
与BrowserRouter as Router
的不同,as
声名别名。
简单例子
先上个简单的例子看一下。
import React from "react";
import { BrowserRouter as Router, Route, Link } from "react-router-dom";
const BasicExample = () => (
<Router>
<div>
<ul>
<li>
<Link to="/">Home</Link>
</li>
<li>
<Link to="/about">About</Link>
</li>
</ul>
<hr />
<Route exact path="/" component={Home} />
<Route path="/about" component={About} />
</div>
</Router>
);
const Home = () => (
<div>
<h2>Home</h2>
</div>
);
const About = () => (
<div>
<h2>About</h2>
</div>
);
export default BasicExample;
简单介绍,BasicExample是对象名,也是该模块导出的模块对象, () => ();
是箭头函数或Lambda表达式。原函数是function():void{}
,即无参的函数。
下面是关于react-router相关概念。
由于每个路由器都会维护一个History对象,其实作用是为了前进
和后退
功能,所以所有组件都必需写在Router(具体是BrowserRouter还是HashRouter由客户定义)
标签里,即BrowserRouter 必需是最外层标签,只能这里才能前进后退
。
而且Router
下只能有一个子标签child
。
Link用于跳转,类似a标签的href的功能。Route在整体上拦截路由请求。
BrowserRouter和HashRouter路由器
BrowserRouter
和HashRouter
是Router
路由器的2种类型。
2种路由的特点
1. 只能有一个子child.比如
<Router>
<div>
</div>
</Router>
- 区别于下面要讲的路由标签
Route
。
两者区别
BrowserRouter
是使用 React-Router
的应用推荐的 history
方案。它使用浏览器中的 History API 用于处理 URL,创建一个像localhost:8080/list/123
这样真实的 URL 。这很容易出现刷新页面后报404的错误。因为真实请求会向服务器发送请求,但服务器根本没有这个页面所以会报错,这是使用BrowserRouter路由的坑点。
想解决这个问题参考这里React-Router browserHistory浏览器刷新出现页面404解决方案,其本质的原理就是利用服务端将任何请求都指向index.html,而在React应用中index.html又刚好通过React-Router
配置了相应的路由,我们让服务器返回index.html
,后面就交给前端路由来实现无刷新加载对应页面。
HashRouter
使用 URL 中的 hash(#)
部分去创建路由,举例来说,用户访问本地服务/about
,实际会看到的是http://localhost/#/about
。
总结一下
假如有一个 Link 标签,点击后跳转到 /test/about。
BrowserRouter: http://localhost:8080/test/about
HashRouter: http://localhost:8080/#/test/about
如果有服务器端的动态支持,建议使用 BrowserRouter,否则建议使用 HashRouter。
Route
要点:
1. 可以放在页面任意位置
2. 匹配URL里的路径名(即域名之后部分),只要匹配就会被渲染,除非在条件语句里。
3. Route标签更多的用于渲染页面,跳转用Link
语法如下
<Route exact path="路径" component={React组件} />
exact:可选参数,决定是否是精确匹配,不填就是模糊匹配,
例如<Route path="/test" component={Test} />
1. 当路径名为’/’时, path不匹配
2. 当路径名为’/test'
或'/test/1'
时, path
匹配
若只想匹配/test
则使用exact
参数,即<Route exact path="/test" component={Test} />
match值对象
当匹配成功后,匹配的结果封装到一个叫match对象里。而这个match对象可以传到component对象的react组件里。
match包含的信息有如下几点:
1. url
:与当前location
路径名所匹配部分
2. path
:路由的地址
3. isExact
:path
是否等于 pathname
4. params
:从path-to-regexp
获取的路径中取出的值都被包含在这个对象中。
例如:
<Route path={`test/:topicId`} component={Topic} />
如’test/:topicId
‘中:topicId
这种写法意味着/test/后的路径名将会被获取并存在match.params.test
中。例如,路径名’/test/6’会获取到一个对象{ topicId: '6' }
而Topic组件声明,接收match对象,获得topicId值如下:
const Topic = ({ match }) => (
<div>
<h3>{match.params.topicId}</h3>
</div>
);
不同的组件提供形势访问方式不同
Route component
组件使用 this.props.match
Route render
纯函数使用match对象 as ({ match }) => ()
Route children
一个返回React element的函数使用match对象as ({ match }) => ()
Route确认渲染哪个组件方式
当满足path条件时,决定渲染哪个React组件有3种方式,其实是指定不同的参数
1. component
: 指定React
组件。即component={组件名}
,最终使用React.createElement创建。例如<Route path="/test" component={Test} />
2. render
: 一个返回React element
的函数。当匹配成功后调用该函数。该过程与传入component参数类似,并且对于行级渲染与需要向元素传入额外参数的操作会更有用。使用render参数的组件则会调用render函数。
例如 :
<Route path='/page' render={(props) => (
<Page {...props} data={extraProps}/>
)}/>
或
<Route path="/one" render={() => <h3>One</h3>} />
- children : 一个返回React element的函数。与上述两个参数不同,无论route是否匹配当前location,其都会被渲染。用的少。
嵌套使用Route
例如
React.render((
<Router>
<Route path="/" component={App}>
<IndexRoute component={Dashboard} />
<Route path="about" component={About} />
<Route path="inbox" component={Inbox}>
{/* 使用 /messages/:id 替换 messages/:id */}
<Route path="/messages/:id" component={Message} />
</Route>
</Route>
</Router>
), document.body)
其中IndexRoute
匹配”/
“路径,即根目录。
路由匹配方式
- 路由器按照先后顺序匹配
- 如果使用绝对路径,可直接找到,如果使用相当路径,要从父路径开始拼完整路径。
- 路径语法
:paramName
: 匹配一段位于 /、? 或 # 之后的 URL。 命中的部分将被作为一个参数()
:在它内部的内容被认为是可选的*
: 匹配任意字符(非贪婪的)直到命中下一个字符或者整个 URL 的末尾
例如
<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
Link
当你点击Link
时,URL会更新,组件会被重新渲染,但是页面不会重新加载。只要用在TAB页面或导航页上切换页面
语法
<Link to="{location}">
一个基本的location对象为{ pathname: '/', search: '', hash: '', key: 'abc123' state: {} }
当直接输入字符串路径
例如/login,会转换成location
对象{ pathname: '/login'}
尽量使用绝对路径,即“/路径
”