React路由
一、路由基本使用
1.依赖安装
yarn add react-router-dom
2.路由分类
1.底层原理不一样:
BrowserRouter使用的是H5的history API,不兼容IE9及以下版本。
HashRouter使用的是URL的哈希值。
2.path表现形式不一样
BrowserRouter的路径中没有#,例如:localhost:3000/demo/test
HashRouter的路径包含#,例如:localhost:3000/#/demo/test
3.刷新后对路由state参数的影响
(1).BrowserRouter没有任何影响,因为state保存在history对象中。
(2).HashRouter刷新后会导致路由state参数的丢失!!!
4.备注:HashRouter可以用于解决一些路径错误相关的问题。
3.路由基本使用
a.统一路由器
将所有路由标签放置在同一个路由器中管理,App的最外侧包裹了一个或
b.基本路由标签使用
<Link to="/home"></Link>
<Route path="/home" component={Home}/>
c.路由匹配方式
// 路由匹配方式
当地址栏为 localhost:3000/home/news
匹配时 忽略 / ,提取出 home news 按顺序匹配
当是模糊匹配时
/home/news // 提取 home news 匹配
/home/news/1 // 提取 home news 1 匹配
/home/1/news // 提取 home 1 news 不匹配
二 、路由组件与一般组件
写法:
一般组件:<Demo />
路由组件:<Route path="/demo" component={Demo} />
存放位置:
一般组件:components
路由组件:pages
接收到的props不同
一般组件:使用组件时,传递了什么属性,就能收到收到什么
路由组件:接收三个固定属性
history:
go: ƒ go(n)
goBack: ƒ goBack()
goForward: ƒ goForward()
push: ƒ push(path, state)
replace: ƒ replace(path, state)
location:
pathname: "/about"
search: ""
state: undefined
match:
params: {}
path: "/about"
url: "/about"
三、NavLink与封装NavLink
NavLink可以实现路由链接的高亮,通过activeClassName指定样式名
1.使用NavLink
<NavLink className='list-group-item' to="/about" activeClassName='atguigu'>About</NavLink>
<NavLink className='list-group-item' to="/home" activeClassName='atguigu'>Home</NavLink>
{/* navlink 默认给点击的标签加一个active类名 默认值 activeClassName='active' */}
2.封装NavLink
因为每一个NavLink 都会有很多相同的属性
<NavLink className='list-group-item' activeClassName='atguigu' {...this.props} /> // {...this.props} 将获取到的所有props属性,都放入NavLink上
// children属性,就是标签体的内容
使用封装后的MyNavLink
<MyNavLink to="/about" a={10} b={'jiang'}>About</MyNavLink>
// 这里标签体的内容 可以从this.porps.children获取
四、Switch使用
1.swith使用原因
1.通常情况下,path与component是一一对应关系
2.Switch可以提高路由匹配效率
2.加入标签
<Switch>
<Route path="/about" component={About} />
<Route path="/home" component={Home} />
{/* 因为有switch包裹,匹配到一个路径后,不在再向下匹配 */}
<Route path="/home" component={Test} />
</Switch>
五、页面样式丢失
多级路径刷新页面样式丢失的问题,public/index.html中的样式使用了./css/style.css,使用了相对路径时
由于使用了多级路径的路由,导致刷新后,加载css路径错误,而路径错误时,服务器返回index.html页面代码,样式失效。
1.问题解决
1.public/index.html 中 引入样式时不写 ./, 改写成 / //然后这会一直是相对于端口的地址,不会被后面的路径不会影响
2.public/index.html 中 引入样式时不写 ./, 改写成 %PUBLIC_URL% //这个保持总是public文件夹下的路经
3.使用HashRouter //应为#后面的路径不会带给服务器,所以不会影响相对路径
六、路由的严格匹配与模糊匹配
1.路由默认使用的是模糊匹配(简单记:[to的路径] 必须包含 [path的路径],且匹配顺序一至)
2.开启严格匹配: <Route exact path="/about" component={About} /> // 知道就行,一般不会开启
3.开启会导致无法继续匹配二级路由
七、Redirect使用
1.使用功能
一般卸载所有路由注册的最下方,当上方其它的所有路由都未匹配成功时,就会跳转到Redirect指定的路由
2.具体编码
<Switch>
<Route path="/about" component={About} />
<Route path="/home" component={Home} />
{/* 都没有匹配到时,匹配Redirect 一上来就是3000/ 就谁也匹配不了,就走/about */}
<Redirect to="/about" />
</Switch>
八、多级路由
1.多级路由注意
1.注册子路由时要写上父路由的path值
2.路由的匹配是按照注册路由的顺序进行的
2.具体编码
{/* 先时App 的路由注册 通过匹配到/home 进入Home组件后 ,再注册了 /home/news路由,再次匹配 */}
{/* 故,使用了严格匹配后,就不能继续匹配二级路由 */}
{/* 注册路由 */}
<Switch>
<Route path="/home/news" component={News} />
<Route path="/home/message" component={Message} />
<Redirect to="/home/news" />
</Switch>
九、路由组件参数传递
1.params参数
路由链接(携带参数):<Link to='/demo/test/tom/18'}>详情</Link>
注册路由(声明接收):<Route path="/demo/test/:name/:age" component={Test}/>
接收参数:this.props.match.params
2.search参数
路由链接(携带参数):<Link to='/demo/test?name=tom&age=18'}>详情</Link>
注册路由(无需声明,正常注册即可):<Route path="/demo/test" component={Test}/>
接收参数:this.props.location.search
备注:获取到的search是urlencoded编码字符串(?name=tom&age=18),需要借助querystring库解析(使用方式参https://www.jianshu.com/p/15a537496131)
3.state参数
路由链接(携带参数):<Link to={{pathname:'/demo/test',state:{name:'tom',age:18}}}>详情</Link>
注册路由(无需声明,正常注册即可):<Route path="/demo/test" component={Test}/>
接收参数:this.props.location.state
备注:刷新也可以保留住参数
十、编程式路由导航
1.基本API
借助this.prosp.history对象上的API对操作路由跳转、前进、后退
-this.prosp.history.push()
-this.prosp.history.replace()
-this.prosp.history.goBack()
-this.prosp.history.goForward()
-this.prosp.history.go()
2.具体编码
<button onClick={this.pushShow(msg.id, msg.title)}>push</button>
<button onClick={this.replaceShow(msg.id, msg.title)}>replace</button>
replaceShow = (id, title) => {
// replace 跳转 + 携带params参数
return (e) => this.props.history.replace(`/home/message/detail/${id}/${title}`);
// replace 跳转 + 携带search参数
// return (e)=>this.props.history.replace(`/home/message/detail?id=${id}&title=${title}`);
// replace 跳转 + 携带state参数
// return (e)=>this.props.history.replace(`/home/message/detail?id=${id}&title=${title}`,{id,title});
}
pushShow = (id, title) => {
// push 跳转 + 携带params参数
return (e) => this.props.history.push(`/home/message/detail/${id}/${title}`);
// push 跳转 + 携带search参数
// return (e)=>this.props.history.push(`/home/message/detail?id=${id}&title=${title}`);
// push 跳转 + 携带state参数
// return (e)=>this.props.history.push(`/home/message/detail?id=${id}&title=${title}`,{id,title});
}
3.withRouter使用
a.withRouter功能
将一般加工成路由组件,让其再props上传递了三个属性location,history,match
b.具体编码
class Header extends Component {
render() {
return (
<div className="page-header">
<h2>React Router Demo</h2>
<button onClick={this.back}>回退</button>
<button onClick={this.forward}>前进</button>
<button onClick={this.go}>Go</button>
</div>
)
}
back = () => {
this.props.history.goBack();
}
forward = () => {
this.props.history.goForward();
}
go = () => {
this.props.history.go(1); // 正数前进,负数后退,数字表示进退步数
}
}
// 将Header加工成路由组件,让其再props上传递了三个属性location,history,match
export default withRouter(Header)