React路由
Posted ~往无前
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了React路由相关的知识,希望对你有一定的参考价值。
React路由:
一、前端路由的工作原理:
其实是利用前端中的BOM对象中的history这个属性来进行的实现。
二、实现前端路由的两种方法:
方法一:直接使用H5推出的history身上API。但是有些旧的浏览器可能不支持。这里使用的BrowserRouter
方法二:hash值(锚点)。兼容性好,会在url地址中出现#字符。使用的是HashRouter。URL的哈希值,#后面的内容不会发送给服务器,但是浏览记录会保存在历史记录中。
BrowserRouter与HashRouter的区别:
除了上面提到的不同之外,刷新后对路由state参数的影响也是不同的:
1.BrowserRouter没有任何影响,因为state保存在history对象中。
2.HashRouter刷新后会导致路由state参数的丢失。
备注:HashRouter可以用于解决一些路径错的相关的问题。
三、react-router-dom:
有三个版本:web,native,anywhere
yarn addd react-router-dom
1.react的插件库
2.专门用来实现一个SPA应用
3.基于React的项目基本都会使用到此库。
四、项目中路由的使用
//在react中router有两种,所以在应用的时候需要声明到底是哪一种router:BrowserRouter,HashRouter
import {Link,BrowserRoueter,Route} from 'react-router-dom'
import Home form './pages/Home'
import About from './pages/About'
//在return的虚拟dom中
<Link className="list-group-item" to="/about">About</Link>
<link className="list-group-item" to="/home">Home</link>
//显示区 注册路由
<div className="panle-body">
<Route path="/about" component={About}/>
<Route path="/home" component={Home}/>
</div>
//为了实现路由的跳转,还要进行BrowerRouter属性的设置。在App的外部包裹一个BroswerRouter
设置的方法一:在最外层的index.js中引入BrowserRouter这个属性,表示App组件中的所有的路由跳转都包含在该属性中。
index.js
//引入BrowserRouter
import {BrowserRouter} from 'react-router-dom'
//引入App
import App from './App'
ReactDOM.render(
<BrowserRouter>
<App/>
</BrowserRouter>
),document.getElementById("root")
上面的Home和About组件都是通过路由的方式渲染的,所以称为路由组件。一般来说,路由组件不放在coponents文件夹下面,而是放在pages文件夹下面。
一般组件和路由组件最大的区别就是在props上面。以班组件需要手动添加props内容才能收到props,但是路由组件,即使没有传递props也可以接收到props。其中有三个属性,分别是history,location,match。
history: //进行路由跳转时使用
go:
goBack: //返回上一级
goForward://到达下一级路由
push://跳转到指定路由
replace://跳转到指定路由,不留历史记录
location:
pathname:'/about', //路由路径
search:"" //使用search方式传递参数时,数据保存在这里
state:undefined //路由传递参数
match:
isExact:true,
params:{},
path:"/aboute",
url:"/about"
五、现在要实现点击nav之后点击的哪个元素实现高亮效果。
1.将标签Link换成标签NavLink。在使用之前首先要将该属性给引入。import {NavLink} from 'react-router-dom'
<NavLink activeClassName="hello" className="list-group-item" to="/about">About</NavLink > //点谁就给谁添加高亮的类名
优化:
从上面的写法上看,发现当有多个路由组件的时候,每次都要写其中的高亮类名或者其他公用的属性,这里看起来就不是很好,我们解决的方法就是自己封装一个组件。
1.封装NavLink组件叫做myNavLink
import {NavLink} from 'react-router-dom'
export default class MyNavLink extends Components{
const {to,title} =this.props
render(){
return(
<NavLink activeClassName="hello" className="list-group-item" to={to}>{title}</NavLink> //写法1
<NavLink activeClassName="hello" className="list-group-item" {...this.porps}</NavLink>//写法2:直接将传递过来的参数使用展开的方式添加入属性。
)
}
}
//在界面引入该组件
import myNavLink from './components/myNavLink'
<MyNavLink to="/about" title="About"></MyNavLink>
<MyNavLink to="/home" title="Home"></MyNavLink>
2.上面是通过将属性放在参数中然后利用props的方式获取值的方式。但是还有更加符合规范的写法:
import {NavLink} from 'react-router-dom'
export default class MyNavLink extends Components{
render(){
return(
<NavLink activeClassName="hello" className="list-group-item" {...this.props} ></NavLink> //这里不需要在组件之间写About或者是Home,因为在组件的props中有一个chidren属性,该属性的值就是组件之间的值。
//也就是下面组件传递的About在内部中通过this.props.children能够获取到。且我们通过在组件中设置属性children也可以添加组件之间的值。
)
}
}
//在界面引入该组件
import myNavLink from './components/myNavLink'
<MyNavLink to="/about">About </MyNavLink> //不通过title属性传递了
<MyNavLink to="/home"> Home </MyNavLink>
六、注册路由时注意的问题:
当注册的路由有多个时候,常在注册路由的包裹一个父级标签,switch
<Switch>
<Route path="/about" component={About}/>
<Route path="/home" component={Home}/>
<Route path="/home" component={Home}/>
</Switch>
//当路由进行匹配的时候,正常情况下都会从上面往下扫描,一旦发现相同的路径则匹配成功。跳转到相应的页面中。加入Switch标签后,一旦发现相同的路径则不会继续往下匹配。
七、解决多级路径刷新页面样式丢失的问题
在路由中的路径写成多级的形式的时候,每次刷新页面都出现页面样式丢失的问题。
解决方法:
1.将index.html页面中的样式引入相对路径改为绝对路径
2.在路径前面加一个%PUBLIC_URL%/
3.直接改用HashRoute这种模式,这样就不会将主机名和端口号后面的内容传递给服务器。
八、路由的模糊匹配和精准匹配
如果是模糊匹配,比如在匹配路径的时候,从左往右匹配,只要遇到相同的路径名称,就可以成功匹配。
如果是精准匹配,需要给路由加一个属性 exact={true}
在匹配的时候只有路径完全相同才能进行匹配,否则无法匹配。
<Route exact path='/about'/> //精准匹配
严格匹配不要随便开启,需要再开,有些时候开启会导致无法继续匹配二级路由。
九、重定向Redirect
import {Redirect} from 'react-router-dom'
<Route path="/about" component={About}/>
<Route path='/home' component={Home}/>
<Redirect/> //重定向标签,当无法匹配到上面的路径时,默认情况下是该路径下面的组件进行匹配。
10、嵌套路由
- 注册子路由时要写上父路由的path值
- 路由的匹配是按照注册路由的顺序进行的
11.路由参数
1.由路由组件传递params参数
//在路由跳转的时候携带参数到指定的页面 向路由组件传递params参数
<Link to={`/home/message/detail/${msgob.id}/${msgobj.title}`}></Link>
//注册路由时声明接收params参数
<Route path="/home/message/detail/:id/:title" component={Detail}></Route>
//接收参数:在detail组件中获取传递过来的参数
export default class Detail extends Component{
render(){
//所有的params参数都放在了this.props.match.params对象中
const {id,title}=this.props.match.params
return(
<ul>
<li>ID:{id}</li>
<li>titile:{title}</li>
</ul>
)
}
}
2.向路由组件传递search参数
//在路由跳转的时候携带参数到指定的页面,参数的格式的 ?+参数 和ajax请求的参数格式类似,这里叫做search参数
<Link to={`/home/message/detail/?id=${msgObj}&title=${msgObj.title}`}></Link>
//search参数无需声明接收
<Route path='/home/message/detail' component={Detail}></Route>
//接收参数
export default class Detail extends Component{
//接收search参数 参数存放在this.props.location.search这个属性中
console.log(this.props.location.search);//得到的结果是'?id=1&titile=hello'的格式
const {search} =this.props.location;
const {id,title} = qs.parse(search.slice(1))
render(){
return(
<ul>
<li>ID:{id}</li>
<li>titile:{title}</li>
</ul>
)
}
}
}
补充:像上面的 key=value&key=value
这种格式的字符串叫做urlencoded格式,有一个专门处理这种数据格式库qs
import qs from 'querystring'
let obj={name:"tom",age:18}
qs.stringfy(obj); //将json格式的数据转换为urlencoded编码格式
let str='carName=奔驰&price=199'
qs.parse(str);//将urlencoded编码格式的数据转换为json格式 {carName:'奔驰',price=199}
3.向路由传递state参数
state参数的特点就是参数不存在路径当中
备注:刷新也可以保留住参数
这里的state跟组件中的state不是一个东西。
//向路由组件传递state参数
<Link to={{parthname:'/home/message/detail',state:{id:msgObj.id,title:title}}}></Link>
<Route path='/home/message/detail' component={Detail}></Route>
//接收state参数
export default class Detail extends Component{
//接收search参数 参数存放在this.props.location这个属性中
const {id,title} =this.props.location.state;
render(){
return(
<ul>
<li>ID:{id}</li>
<li>titile:{title}</li>
</ul>
)
}
}
}
12、路由跳转的两种模式push
、replace
路由的push操作是将每次点击的路径加入到栈中保存,最新的路由路径在最上面。在默认情况下,路由的跳转是push类型。只有添加特定的属性从而转换成replace的类型
<Link replace to={{pathname:'/home/message/detail',state:{id:msgObj.id,title:msgObj.title}}></Link>
这样就不会在栈中保留历史痕迹。
13、编程式导航
上面的案例都是声明式导航,编程式导航和声明式导航不同的点在于,声明式导航需要有人点击才能发生跳转,业务需求有时候需要自动跳转,或者是其他的情况,这时候就需要用到了编程式导航。
<button>push查看</button>
<button onClick={this.replaceShow}>replace查看</button>
replaceShow=(id,title)=>{
//编写一段代码,让其实现跳转到Deatil组件,且为replace跳转携带params参数
//上面我们知道路由组件中的props有三个属性,利用这些属性实现跳转
this.props.history.replace(`home/message/detail/${id}/${title}`)
//同样的跳转方式,携带search参数
this.props.history.replace(`home/messege/detail?id=${id}&title=&{title}`)
//同样的跳转方式。携带state参数
this.props.history.replace('home/message/detail',{id,titile})
}
//使用push跳转,所有携带参数跳转的写法和上面的replace写法类似
pushShow=(id,titile)=>{
this.props.history.push('home/message/detail',{id,title})
}
//回退和前进
back=()=>{
this.props.history.goBack()
}
forward=()=>{
this.props.history.goForward()
}
GO=()=>{
//正负号表示前进后退,数值大小表示距离
this.props.history.go(1);//前进一步
this.props.history.go(-1);//后退一步
}
<Button onClick="back">后退</Button>
<Button onClick="forward">前进</Button>
<Button onClick="go">GO</Button>
14、withRouter
withRouter可以加工一般组件,它是一个函数,让一般组件具备路由组件所特有的API,它的返回值一个新的组件。
import {withRouter} from 'react-router-dom'
class Header extends Component{
}
export default withRouter(Header)
以上是关于React路由的主要内容,如果未能解决你的问题,请参考以下文章
使用 Relay 和 React-Native 时的条件片段或嵌入的根容器
[react] Module not found: Can't resolve 'schedule' in 'C:Usersadcaldvmtn7myapp (代码片段