npm install react-router-dom -save-d
创建A和B两个页面
//A.js
import React from 'react';
function A(){
return (
<div>A</div>
);
}
//B.js
import React from 'react';
function B(){
return (
<div>B</div>
);
}
创建一个路由文件router.js
import React from 'react';
import {HashRouter, Route, Switch} from 'react-router-dom';
import A from './a';
import B from './b';
const TestRouter=()=>(
<HashRouter>
<Switch>
<Route exact path="/" component={A}/>
<Route exact path="/b" component={B}/>
</Switch>
</HashRouter>
);
export {TestRouter};
最后在组件的渲染页面,渲染该路由即可
import React from 'react';
import ReactDOM from 'react-dom';
import {TestRouter} from './router/router';
ReactDOM.render(
<Router/>,
document.getElementById('root')
);
此时在页面输入http://localhost:3000/#/
就会看到A页面,输入http://localhost:3000/#/b
就会看到B页面。url中的#号目前暂不考虑
可以通过a标签进行页面的跳转,如下修改A页面就可以通过点击A页面中的A
来实现跳转到B页面了
//A.js
import React from 'react';
function A(){
return (
<div>
<a href='#/b' >A</a>
</div>
);
}
react-router-dom中提供了Link标签也可以提供页面的跳转,Link的底层还是使用的a标签。
如下面修改B页面,就可以实现点击B跳到A页面
//B.js
import React from 'react';
function B(){
return (
<div>
<Link to='#/'>B</Link>
</div>
);
}
react-router-dom中提供了hashHistory
,设置给组件的history
属性,然后同过改变this.props.history
参数,用来实现页面的跳转.
//在router.js文件中给 HashRouter引入history属性
...
import {HashRouter, Route, Switch, hashHistory} from 'react-router-dom';
...
<HashRouter history={hashHistory}>
...
//A.js
import React from 'react';
function A(props){
return (
<div>
<a href='#/b' >A</a>
<button onClick={() => props.history.push('b')}>test</button>
</div>
);
}
这样点击test按钮就可以使用向B页面的跳转了
其中改变this.props.history
参数的方法有:
在上面router.js文件中,我们只是配置了路由的绝对路径,有些时候我们在跳转某个路由时还要接收一些参数,该怎么处理呢?简单的可以通过在路由后追加’/:key’,然后再路由对应的组件通过this.props.match.params.key
来接收到相应的参数值
如下,我们给B页面传递name
参数。
//router.js
const TestRouter=()=>(
<HashRouter>
<Switch>
<Route exact path="/" component={A}/>
<Route exact path="/b/:name" component={B}/>
</Switch>
</HashRouter>
);
...
//B.js
import React from 'react';
function B(props){
return (
<div>
B
<p>我接收的参数是{props.match.params.name}</p>
</div>
);
}
当然如果传递多个参数就再追加即可
<Route exact path="/b/:name/:age" component={B}/>
这样皆可以通过http://localhost:3000/#/b/afei/21
来访问到afei和age了,
这种方式虽然可以实现传参,但是稍微少传一个参数就会报错。
如果是使用Link标签如何传参呢,很简单使用query关键 字即可
//B.js
import React from 'react';
function B(){
return (
<div>
<Link to={path:'/a',query:{name:'afei',age:19}}>B</Link>
</div>
);
}
并且总觉得的不如http://localhost:3000/#/b?name=afei&age=19
来的方便。(日后补上)
那如果是通过函数跳转是,如何传参呢?很简单,在触发时给history传递对象,然后再对应的页面通过this.props.history.location.state
获取即可,如下
//A.js
<button onClick={() => props.history.push(
{
pathname:'/b',
state:{
name:'afei',
age:18
}
}
)}>test</button>
//B.js
import React from 'react';
function B(props){
return (
<div>
B
<p>我的名字是{props.history.location.state.name}</p>
<p>我的年龄是{props.history.location.state.age}</p>
</div>
);
}
注意上边两种方式传参和接参方式不能混了
有一个现象当我们的router.js使用HashRouter时,我们可以通过浏览器地址栏直接键入url来访问任意路由
//HashRouter
import React from 'react';
import {HashRouter, Route, Switch} from 'react-router-dom';
import A from './a';
import B from './b';
const TestRouter=()=>(
<HashRouter>
<Switch>
<Route exact path="/" component={A}/>
<Route exact path="/b" component={B}/>
</Switch>
</HashRouter>
);
export {TestRouter};
此时
当我们可以输入http://localhost:3000/
时,地址栏会自动变为http://localhost:3000/#/
进行正常访问;
当地址栏输入http://localhost:3000/#/
可以正常访问A页面
当地址栏输入http://localhost:3000/#/b
可以正常访问B页面
但是当我们的router.js中将HashRouter换成BrowserRouter时,就会出现意外。
...
import {BrowserRouter, Route, Switch} from 'react-router-dom';
...
<BrowserRouter>
<Switch>
<Route exact path="/" component={A}/>
<Route exact path="/b" component={B}/>
</Switch>
</BrowserRouter>
表现为:
http://localhost:3000/
时,可以正常访问A页面http://localhost:3000/b
不能正常访问B页面,报错Cannot GET/b
B
的形式,可以正常访问B页面神不神奇,为什么HashRouter可以直接访问路由,而BrowserRouter访问不到?
这是应为BrowserRouter每次改变路由时,会向服务器请求该路由,服务端没有该路径的资源,自然会报错了。当然可以开启一个服务,路由对应的路径下放置资源文件,此错误就会消失。
而使用HashRouter时,会在路径后边添加/#/
,并且/#/
及后边的内容是不会发送给服务器的,当访问http://localhost:3000/#/b
时,其实服务器端收到的依然是http://localhost:3000
,/#/
及后边的内容
会直接在前端进行处理区分。
但是官方却还是推荐我们使用BrowserRouter,这就和它们内部的机制有关了
pushState
、replaceState
、popState
来完成UI和URL的同步下章细讲
下面的内容只做了解
history接口允许操作浏览器的曾经在标签页或者框架里访问会话历史记录。它有一些自己的属性,这里是说一下比较重要的History.state
和History.length
state
是一个只读属性,访问该属性会返回一个表示历史堆栈顶部的状态的值。它可以不必等待popstate
事件而查看状态的方式length
是一个只读属性,表示会话历史中元素的数目,包括当前的加载页。下面来看history中三个比较重要的方法
总的来说可以将history看作是维护浏览器历史记录的管理器。
URL 接口是一个包含若干静态方法的对象,用来创建 URLs。它的属性主要是实现URLUtils 中定义的属性,包括:
href:包含完整URL的字符串
host:包含URL域名+“ : ”+端口号的字符串
Hostname:包含URL域名的字符串
port:包含URL端口号的字符串
pathname:以/
起头紧跟URL文件路径的字符串
search:以?
起头紧跟URL文件路径的字符串
hash:以#
起头紧跟URL文件路径的字符串
username:包含在域名前面指定的用户名字符串
password:包含在域名前面指定的密码字符串
origin:只读属性,返回一个包含协议名、域名和端口号的字符串
searchParams:返回一个用来访问当前URL GET请求参数的 URLSearchParams
对象。
URL还有一些静态方法,不再赘述。这里只需要明白所谓的#
是URL的hash属性的规范,就跟seacrh的?
一样。
参考:
https://www.jianshu.com/p/8954e9fb0c7e
https://reacttraining.com/react-router/web/api/BrowserRouter
https://www.cnblogs.com/soyxiaobi/p/11096940.html
https://developer.mozilla.org/zh-CN/docs/Web/API/History
https://developer.mozilla.org/zh-CN/docs/Web/API/URL