单页应用与多页应用
单页应用
只有1个壳页面,使用前端路由控制多个组件切换。优点是:
- 所有页面共享公共资源,页面跳转只刷新局部,加载速度快。
- 便于页面间共享数据。
缺点是: - SEO不方便。
- 需要特定框架协助开发,以实现路由功能。
多页应用
是传统开发方法,有多个入口文件,使用后端路由决定返回哪个页面。优点是:
- 便于SEO。
- 开发难度低。
缺点是: - 每个页面都需要独自加载公共资源,加载速度慢。
- 页面间共享数据不方便。
前端路由React Router
routers
解决“全局配置”的问题。
// 写在App.js中
export default () => {
return (
<BrowserRouter>
route matchers...
</BrowserRouter>
)
}
<BrowserRouter>
BrowserRouter基于HistoryAPI。
跳转
:先调用history.pushState()
创建1个history entry
,同时改变地址栏,然后调用history.go(1)
访问它,触发popstate event
,使window.onpopstate
执行,从而改变UI。
重定向
:先调用history.replaceState()
改变当前的history entry
,同时改变地址栏,然后调用history.go(0)
访问它。
BrowserRouter使用正常的URL,类似于http://example.com/page
,这样的URL会全部发送给服务器,所以要配置服务器,使其无论接受什么URL都返回同一页面,否则报404。
```getUserConfirmation(function(message, callback))```:定义在跳转前弹出对话框的实现,默认是基于```window.confirm()```实现。```window.confirm()```显示一个具有一个可选消息和两个按钮(确定和取消)的模态对话框。例如:
// message 是要在对话框中显示的可选字符串 // result 是一个布尔值,表示是选择确定还是取消 result = window.confirm(message);
```forceRefresh(bool)```:如果为```true```,那么跳转时会整页刷新。默认是```true```。
```keyLength(number)```:```location.key```的长度。默认是```6```。
```children(node)```:要渲染的子元素,包括```Switch```、```Route```。
###### \<HashRouter>
HashRouter基于HTMLAnchorElement.hash。
Examples const anchor = document.getElementById(“myAnchor”) // Getter: #Examples string = anchor.hash // Setter anchor.hash = string
HashRouter使用的URL类似于```http://example.com#page```,这样的URL只会发送```#```前面的部分给服务器,所以不需要配置服务器。
```basename(string)```、```getUserConfirmation()```、```children(node)```同上。
```hashType(string)```:```window.location.hash```的编码方式。```slash```例如```#/sunshine/lollipops```;```noslash ```例如```#sunshine/lollipops```;```hashbang```例如```#!/sunshine/lollipops```。
#### route matchers
解决“如何匹配URL”“哪个URL对应哪个组件”的问题。
// 写在App.js中
export default () => {
return (
###### Switch
如果```Route```在```Switch```中,那么会从当前所在的页面对应的```Route```开始向下寻找,只渲染第一个匹配的```Route```。
如果不用```Switch```包裹```Route```,那么所有能匹配的```Route```都会被渲染。
```location(object)```:默认时用当前栈顶的```location```进行匹配;如果传了这个值,就用传的值进行匹配。
```children(node)```:```Route```或```Redirect```。
###### Route
```routeProps(object)```:```component```、```render```、```children```接受的function都会以它为参数。包含```match```、```location```、```history```。
```component(function)```:输入routeProps,返回模板。在每次render时,如果```location```匹配,就以这个function为参数调用```React.createElement()```创建一个新组件,并卸载已经存在的组件。
function Fun(routeProps) { return (模板) }
<Route path=”…” component={Fun} />
```render(function)```:输入routeProps,返回模板。在每次render时,如果```location```匹配,就更新已经存在的组件。
<Route path=”…” render={routeProps => (模板)} />
```children(function)```:输入routeProps,返回模板。在每次render时,无论```location```是否匹配,都会创建一个新组件,并卸载已经存在的组件。 不匹配时,```routeProps.match```为```null```。
<Route path=”…” children ={routeProps => (模板)} />
```path(string)```:用于匹配URL的path。默认匹配任何URL。
```exact(bool)```:当```true```时,匹配整个URL;否则,只匹配URL的begin。
```strict(bool)```:当```true```时,如果path末尾有```/```,那么URL末尾也要有```/```才能匹配。
```sensitive(bool)```:当```true```时,大小写敏感。
#### navigation
###### \<Link>
等价于```a标签```。点击后,默认会添加1个URL为```host[:port]/basename/to```的```history entry```,并访问。
Home</Link>
```to(string)```:用1个字符串创建```location```用于路由匹配,包括```pathname```、```search```、```hash部分```。
```to(object)```:创建用于路由匹配的```location```,包括```pathname```、```search```、```hash部分```和```state```。
```to(function(location))```:返回代表新的```location```的对象或字符串。
```replace(bool)```:当```true```时,会改变当前的```history entry```而不是添加。默认```false```。
```component(React.Component)```:基于```a标签```自定义地实现导航标签。
```other```:其它的```a标签```的属性,例如```title```、```id```、```className```等。
###### \<NavLink>
如果当前URL是匹配```to```的,那么```NavLink```会变成```activeClassName```指定的样式。
```activeClassName(string)```: 。
```activeStyle(object)```: 。
```exact(bool)```:当```true```时,只有精确匹配才会显示指定的样式。
```strict(bool)```:同```Route strict```。
```isActive(function(match, location))```:决定链接是否激活的额外逻辑。
```location(object)```:默认是比较栈顶的```history entry```的```location```。当传这个参数时,就是与传的```location```作比较。
###### \<Redirect>
不需要模板,因为不渲染任何东西,只重定向。
```to(string)```:要重定向到的```path```。
```to(object)```:要重定向到的```location```。
```push(bool)```:当```true```时,会创建新的```location```而不是修改当前的。
```from(string)```:当```Redirect```用在```Switch```中时,相当于```path```,用于匹配。
```exact(bool)```:同上。
```strict(bool)```:同上。
```sensitive(bool)```:同上。
#### 官方文档中的其它问题
###### Scroll Restoration
解决“跳转之后Scroller应该滚动到哪”的问题。
###### Server Rendering
解决“服务端渲染的路由应该如何做”的问题。
## 动态路由
###### 静态路由
在APP初始化阶段声明“组件与URL的匹配关系”,匹配关系一旦声明就不可改变。
###### 动态路由
在APP运行阶段,为组件的```props```添加```path```,说明本组件与哪个URL匹配,匹配关系可以在运行时动态改变的。
```动态路由```可实现```嵌套路由```、```响应式路由```。
###### 嵌套路由
嵌套路由可实现局部刷新。
URL的path部分嵌套,形如:/path1/path2;其中,path1与component1对应,path2与component2对应,component1与component2嵌套。
当访问/path1/other时,刷新component1和other component;再访问/path1/path2时,只刷新component2。
###### 响应式路由
相同的```path```在不同尺寸的屏幕上应该显示不同的UI/组件。例如:
<Route path=”/invoices” component={Invoices} />
const Invoices = () => (
<div>
{screenIsSmall => screenIsSmall ? (
// 小屏的UI
## History
```history```管理一个```history stack```,栈中有```history entry```,用来记录用户的“访问历史”。
当访问1个```entry```时,哪个组件能匹配它的```location```,就渲染哪个组件。
#### 访问
// 方式一: const history = useHistory()
// 方式二: const history = props.history
// 方式三: <Route path=”…” render={routeProps.history => {…}} />
// 方式四: <Route path=”…” children ={routeProps.history => {…}} />
#### 字段
```length(number)```:```stack```中的```entry```数量。
```action(string)```:栈顶```entry```的```action```,是```PUSH```、```REPLACE```、```POP```中的一个。
```location(object)```:栈顶```entry```的```location对象```。
#### 方法
```push(path, [state])```:向栈中添加1个```entry```,会改变地址栏中的URL,但不访问它。
```replace(path, [state])```:替换栈顶的```entry```,会改变地址栏中的URL,但不访问它。
```go(n)```:会问向前或向后的第n个```entry```。
```goBack()```:等价于go(-1)。
```goForward()```:等价于go(1)。
## Location
```location```看起来是这样的:
{ key: ‘ac3df4’, // not with HashHistory! pathname: ‘/somewhere’, search: ‘?some=search-string’, hash: ‘#howdy’, state: { [userDefined]: true } }
#### 访问
// 方式一: const location = useLocation()
// 方式二: const location = props.location
// 方式三: <Route path=”…” render={routeProps.location => {…}} />
// 方式四: <Route path=”…” children ={routeProps.location => {…}} />
#### 使用
当```目标UI/组件```不只依赖于```path```还依赖于```state```时,可以把```location```作为参数,实现单页传参。例如:
<Link to={location}/> <Redirect to={location}/> history.push(location) history.replace(location)
## Match
#### 访问
// 方式一: const match = useRouteMatch(path)
// 方式二: const match = useRouteMatch({path:…, exact:…, strict:…, sensitive:… })
// 方式三: const match = props.match
// 方式四: <Route path=”…” render={routeProps.match => {…}} />
// 方式五: <Route path=”…” children ={routeProps.match => {…}} />
#### 字段
```params(object)```:页面间数据传输来的键值对。
```isExact(boolean)```:是否能匹配整个URL。
```path(string)```:用于匹配URL的path。
```url(string)```:被匹配上的URL。
## Path
```path="/"```匹配任何URL,所以这个```Route```应该放在最后。
```path```越短的```Route```应该越靠后。
## 单页传参
#### Query Parameters
数据会在URL中以query形式显示。
// Component1.js 中写数据
SAM</Link>
// /account 对应的 Component2.js 中读数据 let query = useQuery() query.get(“name”) // sam
#### Path Parameters
数据会在URL中以relactivepath形式显示。