声明式路由与编程式路由
- 在原生的
js
中,声明式
与函数式
是有着一条界限的,我们可以认为声明式
就是html
标签实现一个功能,而编程式
就是使用原生js
实现一个功能,就拿页面跳转为例,声明式
就是使用a
标签来实现页面跳转的,而编程式
则是使用location.herf
来实现页面跳转的, 代码如下所示:
<!DOCTYPE html> <html lang="en"> <body> <a style="color: red;" href="http://localhost:3000/#/home/info"> (声明式)点击跳转 </a><hr>
<button id="go">(编程式)点击跳转</button>
<script> var a = document.querySelector('#go')
a.onclick = ()=>{ window.location.href = 'http://localhost:3000/#/home/info' } </script> </body> </html>
|
结果展示:
由上述的案例我们可以得出,无论是声明式
还是编程式
,我们使用原生的js
同样可以实现路由的跳转(只不过路由url
上需要拼接#/
),但是我们一般在项目当中使用路由的跳转都需要知道当前路径更改时的状态,也就是我们能够监听到路径的修改从而做出对应的动作,如当点击对应的按钮跳转页面时,对应的按钮有高亮样式
等…当然我们也可以使用原生的js
来实现(使用window.onhashchange
监听url
上的hash
变化,随后使用location.hash
来获取对应的url
路径 , 这其实就是React
路由的实现原理), 但其实React
已经为我们造好轮子了!!
案例展示:
- 使用
声明式
和编程式
路由实现页面的跳转,声明式路由
负责一级路由的跳转(home页面和about页面
), 编程式路由
则负责二级路由的跳转,两种路由的跳转均携带参数
NavLink
(声明式路由)
官方文当
NavLink
导航组件,它编译生成后的html
标签只能是 a
,但是它有激活样式,也就是activeClassName
(地址栏中的地址和to
属性匹配,就有内置样式名)
切记: NavLink
只能用在Router
的包裹中
父组件(声明式)
import{HashRouter as Router,Route,NavLink,Redirect,Switch} from 'react-router-dom' import React from 'react'
import About from './testPages/about.js' import Home from './testPages/home.js' import NotFound from './testPages/404.js'
export default function App(props) {
return ( <div> <Router> {/* 声明式路由跳转(可以携带参数!) */} <NavLink to={`/user/about?params=${'携带过去的参数'}`}>点击跳转到关于页面(声明式)</NavLink>
{/* 使用Switch来解决每次页面刷新,重定向功能执行的bug(模糊匹配) */} <Switch> {/* 多级路由 */} <Route path="/user/about" component={About}/> {/* 一级路由 */} <Route path="/home" component={Home}/>
{/* 路由的重定向(使用exact实现精确匹配) */} <Redirect from="/" to="/home" exact/> {/* 匹配不到的页面则展示404 */} <Route component={NotFound}/> </Switch> </Router> </div> ) }
|
props.history
(编程式路由)
- 官方文档
- 编程式路由跳转一般用于嵌套路由,一级路由(
父组件
)通过props
将路由跳转的方法(history
)传给二级路由(子组件
),随后在二级路由中调用对应的方法来进行页面的跳转
子组件(编程式)
import React from 'react'
import{HashRouter as Router,Route,Redirect,Switch,useHistory} from 'react-router-dom'
import About from './about.js' import Info from './info.js' import NotFound from './404.js'
export default function Home(props) { const history = useHistory()
const goRoute = (route)=>{ console.log('父组件提供过来的router方法,用于路由跳转',props);
history.push(route) } return ( <div> 首页 {/* 编程式路由跳转 */} <ul> <li> <button onClick={()=>goRoute(`/home/info?params=${'携带过去的参数'}`)}>info(编程式)</button> </li> <li> <button onClick={()=>goRoute(`/home/about?params=${'携带过去的参数'}`)}>about(编程式)</button> </li> </ul>
{/* 在子组件下设置二级路由调用 */} <div style={{width:'200px',height:'600px',backgroundColor:'skyblue'}}> <Router> {/* 使用Switch来解决每次页面刷新,重定向功能执行的bug(模糊匹配) */} <Switch> {/* 多级路由 */} <Route path="/home/about" component={About}/> {/* 一级路由 */} <Route path="/home/info" component={Info}/>
{/* 路由的重定向(使用exact实现精确匹配),一进入home页面默认跳转到info页面 */} <Redirect from="/home/" to="/home/info" exact/> {/* 匹配不到的页面则展示404 */} <Route component={NotFound}/> </Switch> </Router> </div> </div> ) }
|
结果展示:
动态路由(路由传参
)
- 由上面的案例中我们可以看到,路由的跳转的确可以通过
url
路径来传递参数,但是这样传递参数的话,我们是很难获取到的,需通过字符串截取的方式来获取参数,非常的麻烦,由此便衍生出动态路由
这一说法!
设置方法:
- 在
Route
组件的“path”属性中,我们使用了“users/:params
”,“:
”冒号用于使路由动态化
,并且可以使用冒号后的路由路径中提供的名称“params
”访问参数.
{} <Route path="/user/about/:params" component={About}/>
|
- 在对应的二级路由(子组件)中使用
props
接收并读取
console.log('一级路由(父组件)传过来的数据',this.props.match.params);
console.log('上级路由传过来的数据',props);
|
案例展示:
- 复刻上面的案例,在功能基本一致的情况下,子组件(下级路由)接收并展示父组件(上级路由)传过来的数据并展示出来
- 一级路由(
爷爷级
)
import{HashRouter as Router,Route,NavLink,Redirect,Switch} from 'react-router-dom' import React from 'react'
import About from './testPages/about.js' import Home from './testPages/home.js' import NotFound from './testPages/404.js'
export default function App(props) {
return ( <div> <Router> {/* 声明式路由跳转(可以携带参数!) */} <NavLink to={`/user/about/${'关于数据(声明式)'}`}>点击跳转到关于页面(声明式)</NavLink>
{/* 使用Switch来解决每次页面刷新,重定向功能执行的bug(模糊匹配) */} <Switch> {/* 多级路由 设置动态路由(携带参数) */} <Route path="/user/about/:params" component={About}/> {/* 一级路由 */} <Route path="/home" component={Home}/>
{/* 路由的重定向(使用exact实现精确匹配) */} <Redirect from="/" to="/home" exact/> {/* 匹配不到的页面则展示404 */} <Route component={NotFound}/> </Switch> </Router> </div> ) }
|
- 二级路由(
爸爸级
)
import React from 'react'
import{HashRouter as Router,Route,Redirect,Switch,useHistory} from 'react-router-dom'
import About from './about.js' import Info from './info.js' import NotFound from './404.js'
export default function Home(props) { const history = useHistory()
const goRoute = (route)=>{ console.log('父组件提供过来的router方法,用于路由跳转',props);
history.push(route) } return ( <div> 首页 {/* 编程式路由跳转 */} <ul> <li> <button onClick={()=>goRoute(`/home/info/${'个人信息数据(编程式)'}`)}>info(编程式)</button> </li> <li> <button onClick={()=>goRoute(`/home/about/${'关于数据(编程式)'}`)}>about(编程式)</button> </li> </ul>
{/* 在子组件下设置二级路由调用 */} <div style={{width:'200px',height:'600px',backgroundColor:'skyblue'}}> <Router> {/* 使用Switch来解决每次页面刷新,重定向功能执行的bug(模糊匹配) */} <Switch> {/* 多级路由 设置动态路由(携带参数) */} <Route path="/home/about/:params" component={About}/> {/* 多级路由 设置动态路由(携带参数) */} <Route path="/home/info/:params" component={Info}/>
{/* 路由的重定向(使用exact实现精确匹配),一进入home页面默认跳转到info页面 */} <Redirect from="/home/" to="/home/info/:params" exact/> {/* 匹配不到的页面则展示404 */} <Route component={NotFound}/> </Switch> </Router> </div> </div> ) }
|
- 三级路由(
儿子级
)
import React, { Component } from 'react'
export default class App extends Component { render() { console.log('一级路由(父组件)传过来的数据',this.props.match.params); return ( <div>个人信息页-{this.props.match.params.params}</div> ) } }
|
import React from 'react'
export default function App(props) { console.log('上级路由传过来的数据',props); return ( <div>关于页面-{props.match.params.params}</div> ) }
|
结果展示:
剩余两种路由传参的方法:(不推荐使用
)
(1) this.props.history.push({ pathname : '/user' ,query : { day: 'Friday'} }) this.props.location.query.day (2) this.props.history.push({ pathname:'/user',state:{day : 'Friday' } }) this.props.location.state.day
|
以上两种方法是不推荐使用的,因为他们都存在问题,那就是他们是通过在浏览器混村中创建一个新的变量来保存你想要在路由url
中传递的参数的,也就是说不同的浏览器之间,不同的硬件设备之间,是无法实现数据共享的,也就是说,如果使用以上两种方法来写项目,那么项目完成之后,你通过分享网址的方法将携带参数的网址分享给他人, 他人是无法获取的(进入你分享的网站中!)