SPA
单页Web应用(single page web application,SPA)。
点击页面中的链接不会刷新页面,只会做页面的局部更新。
数据都需要通过ajax请求获取, 并在前端异步展现。
路由的作用
一个路由就是一个k
(路径)与v
(方法/组件)的映射关系,主要用于实现SPA应用。
路由分类:
后端路由。比如javaweb路径映射对应的servlet
前端路由
浏览器端路由,value是component,用于展示页面内容
注册路由: <Route path="/test" component={Test}>
工作过程:当浏览器的path变为/test时, 当前路由组件就会变为Test组件
基本原理:
路由组件与一般组件
写法不同
路由组件: <Route path="/about" component={About}/>
props
属性不同
一般组件,传递什么props,组件接收的到的就是什么
路由组件,固定接收三个props:
history
go(n)
goBack()
goForward()
push(path, state)
replace(path, state)
location
pathname: "/about"
search: ""
state: undefined
match
params: {}
path: "/about"
url: "/about"
使用react-router-dom
Link 路由链接
配置路由器,要想路由生效,必须配置路由器,并且同一应用要使用同一路由器
BrowserRouter
, 通过H5的histroy对象操作历史记录完成
<BrowserRouter>
<App />
</BrowserRouter>
HashRouter
,通过锚点#
完成
<HashRouter>
<App />
</HashRouter>
编写路由链接<Link/>
<Link className="list-group-item" to="/about">About</Link> <!-- 此链接将会跳转到/about路径下 -->
<Link className="list-group-item" to="/home">Home</Link> <!-- 此链接将会跳转到/home路径下 -->
注册路由
<Route path="/about" component={About}/> <!--/about路径将会跳转/展示About组件-->
<Route path="/home" component={About}/> <!--/home路径将会跳跳转/展示Home组件-->
NavLink 导航路由链接
Link
组件不能增加任何的点击事件,可以使用升级版NavLink
。如果指定的NavLink
被触发了点击事件,那么就会默认给NavLink
上增加一个active
的样式类名,从而增加了点击效果
<NavLink className="list-group-item" to="/about">About</Link> <!-- 此链接将会跳转到/about路径下 -->
点击了该路由,会变为:
<NavLink className="list-group-item active" to="/about">About</Link> <!-- 此链接将会跳转到/about路径下 -->
或者通过activeClassName
属性,修改要增加的样式类名:
<NavLink activeClassName="open" className="list-group-item" to="/about">About</Link>
<!-- ↓ 点击将会变成 -->
<NavLink activeClassName="open" className="list-group-item open" to="/about">About</Link>
可以封装NavLink组件,减少代码
Switch 单一匹配
<Switch>
<Route path="/about" component={About}/>
<Route path="/home" component={Home}/>
<Route path="/home" component={Test}/>
</Switch>
通常情况下,path和component是一一对应的关系
当出现一个path对应多个component时,会匹配并展示所有匹配的component
模糊匹配与精准匹配
默认为模糊匹配(输入路径必须包含路由路径):
<NavLink className="list-group-item" to="/about">About</Link>
<NavLink className="list-group-item" to="/home/a/b">Home</Link>
<Switch>
<Route path="/about" component={About}/>
<Route path="/home" component={Home}/>
</Switch>
开启精准匹配(不推荐):
<Switch>
<Route exact path="/about" component={About}/>
<Route exact path="/home" component={Home}/>
</Switch>
Redirect 路由重定向
当所有的路由都匹配不上,就会重定向到Redirect
定义的路径上:
<Switch>
<Route path="/about" component={About}/>
<Route path="/home" component={Home}/>
<Redirect to="/about"/>
</Switch>
多级路由
<!-- App 父组件下的路由 src/pages/home about -->
<Switch>
<Route path="/about" component={About}/>
<Route path="/home" component={Home}/>
<Redirect to="/about"/>
</Switch>
<!-- Home 子组件下的路由, src/pages/home/news message -->
<Switch>
<Route path="/home/news" component={News}/>
<Route path="/home/message" component={Message}/>
<Redirect to="/home/news"/>
</Switch>
路由传参
params参数
注册路由并声明接收
<Route path="/demo/test/:name/:title" component={Test} />
路由链接携带参数
<Link to='/demo/test/tom/18' />
接收参数
const {name, title} = this.props.match.params; // 这里可以只传入id,然后发送接口请求数据
最后会落实到url path params
参数上,所以称为params参数
search参数
注册路由无需声明参数
<Route path="/demo/test" component={Test} >Test</Link>
路由链接携带参数
<Link to='/demo/test?name=tom&age=19' >Test</Link>
接收参数
// 接收search参数
const {search} = this.props.location // ?name=tom&age=19
const {id,title} = qs.parse(search) // 使用querystring解析
state 参数
注册路由无需声明参数
<Route path="/demo/test/:name/:title" component={Test} />
路由链接携带参数
<Link to={{path:'/demo/test', test:{name: "tom", age: 18}}} >Test</Link>
接收参数
this.props.location.state
push
和replace
<li>
<MyNavLink replace to="/home/news">News</MyNavLink> <!-- 默认就是push,这里开启replace,历史记录栈顶将会被替换,而不是新压栈-->
</li>
编程式路由
当路由时间不可以由人触发时,Link和NavLink就无法生效,所以借助路由组件的props.history
对象的api进行操作,让路由组件中的普通组件可以触发相应的路由操作。
注意,只有路由组件有history对象
replaceShow = (id,title)=>{
//replace跳转+携带params参数
//this.props.history.replace(`/home/message/detail/${id}/${title}`)
//replace跳转+携带search参数
// this.props.history.replace(`/home/message/detail?id=${id}&title=${title}`)
//replace跳转+携带state参数
this.props.history.replace(`/home/message/detail`,{id,title})
}
pushShow = (id,title)=>{
//push跳转+携带params参数
// this.props.history.push(`/home/message/detail/${id}/${title}`)
//push跳转+携带search参数
// this.props.history.push(`/home/message/detail?id=${id}&title=${title}`)
//push跳转+携带state参数
this.props.history.push(`/home/message/detail`,{id,title})
}
back = ()=>{
this.props.history.goBack()
}
forward = ()=>{
this.props.history.goForward()
}
go = ()=>{
this.props.history.go(-2)
}
render() {
const {messageArr} = this.state
return (
<div>
<ul>
{
messageArr.map((msgObj)=>{
return (
<li key={msgObj.id}>
<Link to={{pathname:'/home/message/detail',state:{id:msgObj.id,title:msgObj.title}}}>{msgObj.title}</Link>
{/*这里通过onClick事件触发*/}
<button onClick={()=> this.pushShow(msgObj.id,msgObj.title)}>push查看</button>
<button onClick={()=> this.replaceShow(msgObj.id,msgObj.title)}>replace查看</button>
</li>
)
})
}
</ul>
<hr/>
{/* 声明接收params参数 */}
{/* <Route path="/home/message/detail/:id/:title" component={Detail}/> */}
{/* search参数无需声明接收,正常注册路由即可 */}
{/* <Route path="/home/message/detail" component={Detail}/> */}
{/* state参数无需声明接收,正常注册路由即可 */}
<Route path="/home/message/detail" component={Detail}/>
<button onClick={this.back}>回退</button>
<button onClick={this.forward}>前进</button>
<button onClick={this.go}>go</button>
</div>
)
}
withRouter 普通组件操作路由
只有路由组件有history
对象,一般组件需要通过withRouter
函数:
import {withRouter} from 'react-router-dom'
export default withRouter(Header) // 暴露的是一个withRouter包装后的组件
//withRouter可以加工一般组件,让一般组件具备路由组件所特有的API
//withRouter的返回值是一个新组件