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、路由跳转的两种模式pushreplace

路由的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 (代码片段

VSCode自定义代码片段11——vue路由的配置

VSCode自定义代码片段11——vue路由的配置

VSCode自定义代码片段11——vue路由的配置

Redux&React路由器:梳理调度和导航(history.push)