前端路由就是把不同路由对应不同的内容或页面对应展示出来。路由可以帮助我们很好的管理页面和代码,增强用户的体验感。路由模式有hash和 history 两种模式,通常用hash模式。在react中,react-router是跨平台的,内置通用组件和通用Hooks。react-router-dom是在react-router基础上提供了Link和NavLink,而且依赖history库提供了两个浏览器端适用的BrowserRouter和HashRouter,现在的项目基本都是使用react-router-dom。本篇文章介绍了使用频率高和我接触到的路由内容。
一、路由原理
通俗的来说,路由用来管理url地址和视图之间的关系,一个地址对应一个页面要展示的内容,下面展示的地址就是hash模式(/#/)
原理:
1、准备视图(html)
2、准备路由的路线(可以是一个对象,键名是路线名称和值是视图地址)
3、通过hash地址的路线,获取“视图地址”
4、在指定标签中,加载需要的视图页面
原理图:灵魂画手
二、使用
(一)安装
npm i react-router-dom@5
(二)导入
import { ...通用组件 } from 'react-router-dom'
(三)使用
<BrowserRouter ><Route path="路径" component={组件}></Route> </BrowserRouter >
三、通用组件
(一)BrowserRouter
history模式,页面跳转原理是使用了pushState、replaceState。使用这个包裹,路由的形式将以/展示,可以通过as重命名,一般见到的形式为:BrowserRouter as Router(把BrowserRouter 重命名为Router )
**属性:**
basename(string):所有位置的基本url,应用是从服务器上的子目录提供的,则需要将其设置为子目录,格式正确的基本名称应以斜杆开头,但不能以斜杆结尾
getUserConfirmation(fn):用于确认导航的功能,默认使用window.confirm
<BrowserRouter></BrowserRouter><Route path='/films' component={Films}></Route> <Route path='/home' component={Home}></Route>
(二)HashRouter
hash模式,页面跳转原理是使用了location.hash、location.replace。使用这个包裹,路由的形式将以/#/展示,虽然长的丑,但是用的比较多
<HashRouter></HashRouter><Route path='/films' component={Films}></Route> <Route path='/home' component={Home}></Route>
注意:BrowserRouter和HashRouter的区别
1、底层原理不一样
HashRouter使用的是Url的哈希值
BrowserRouter使用的是h5的history api,不兼容ie9及以下版本
2、path表现形式不一样HashRouter带个#号
3、HashRouter刷新后对路由state参数的影响,而BrowserRouter是将state保存再history对象中
4、HashRouter可以用于解决一些路径错误相关的问题
(三)Route
匹配组件,并展示组件。即匹配成功后,组件立即被替换成匹配的组件
属性类型作用pathstr | obj路由匹配路径,没有path属性的Route总是会匹配exactbool为true时,要求全路径匹配(/home)。路由默认为“包含”的(/和/home)都匹配,这意味着多个Route可以同时进行匹配和渲染componentfn | component在地址匹配的时候React的组件才会被渲染,route props也会随着一起被渲染renderfunc内联渲染和包装组件,要求要返回目标组件的使用
<Route path='/films' component={Films} />或者
<Route path="/" exact render={() => {
return <IndexPage user={user} />
}} />
注意:模糊匹配和精准匹配
因为exact的存在,分为模糊匹配和精准匹配
(四)Switch
排他性(单一)匹配。如果不想使用包容性,那么使用Switch,类似于js中的switch分支语句,被包裹在里面的组件会被匹配到一个,并跳出结束,常用于侧边栏,引导选项卡
属性类型作用locationstr | obj
一般我们不会给该组件设置 location 属性。
不设置: Switch组件的子组件(一般是 Route 或 Redirect)会根据当前浏览器的 location 作为匹配依据來进行路由匹配。
设置: Switch 组件的子组件会根据定义的 location 作为匹配依据
<HashRouter></HashRouter>{/* Switch类似于Js里面的Switch分支,被包裹的相当于case,总能匹配到一个,并跳出 */} {/* 这样能做到一个页面出出现一个,不会多个页面展示在一个页面中 */} <Switch> <Route path='/films' component={Films}></Route> <Route path='/home' component={Home}></Route> </Switch>
(五)Redirect
重定向,如用户输入了/,见到/会指定跳转到重新定义的页面,在这里使用了exact,功能精准匹配,只有看到单独是/的才会重定向。模糊匹配,只要含有/就会响应
属性类型作用fromstring来自tostring object去向pushboolean添加历史记录exactboolean严格匹配sensitiveboolean
区分大小写
<HashRouter></HashRouter><Route path='/films' component={Films}></Route> <Route path='/home' component={Home}></Route> {/* 模糊匹配 */} {/* <Redirect from='/' to='/home'/> */} {/* 精准匹配 */} <Redirect from='/' to='/home' exact/>
温馨提示:如果没有子路由的情况,建议大家配都加一个
exact
;如果有子路由,建议在子路由中加
exact
,父路由不加; 而
strict
是针对是否有反斜杠的,一般可以忽略不配置
(六)Link
相当于a标签,在react将虚拟DOM渲染成真实DOM后,Link组件也被渲染成了a标签,常用于导航
属性类型作用tostr | obj{pathname:,search:,hash:}要跳转的路径或地址replacebool是否替换历史记录
<li> <Link to='/films'>电影</NavLink> </li> <li> <Link to='/cimans'>影院</NavLink> </li> <li> <Link to='/home'>我的</NavLink> </li>
(七)NavLink
NavLink方式相当于Link的加强版
属性类型作用tostr | obj{pathname:,search:,hash:}要跳转的路径或地址replacebool是否替换历史记录** activeClassNamestr设置选中样式,默认值为activeactiveStyleobj当元素被选中时,为此元素添加样式 exact****bool为true时,只有当导致和完全匹配class和style才会应用strictbool为true时,在确定为位置是否与当前URL匹配时,将考虑位置pathname后的斜线isActivefun**判断链接是否激活的额外逻辑的功能
<li> <NavLink to='/films'>电影</NavLink> </li> <li> <NavLink to='/cimans'>影院</NavLink> </li> <li> <NavLink to='/home'>我的</NavLink> </li>
(八)withRouter
将一个组件包裹进
Route
里面, 然后
react-router
的三个对象
history, location, match
就会被放进这个组件的
props
属性中.
// withRouter实现原理:
// 将组件包裹进 Route, 然后返回
// const withRouter = () => {
// return () => {
// return <Route component={Nav} />
// }
// }
// 这里是简化版
const withRouter = ( Component ) => () => <Route component={ Component }/>
//withRouter的返回值是一个新组件
如果我们某个东西不是一个
Router
, 但是我们要依靠它去进行浏览记录的前进后退 这时候就可以使用
withRouter
,将一般组件变成路由组件。使用场景:比如点击页面的logo, 返回首页, 这时候就可以使用withRouter来做
import React, { Component } from 'react'
import {withRouter} from 'react-router-dom' //引入withRouter
class Header extends Component {
back = ()=>{
this.props.history.goBack()
}
forward = ()=>{
this.props.history.goForward()
}
go = ()=>{
this.props.history.go(-2)
}
render() {
console.log('Header组件收到的props是',this.props);
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>
)
}
}
export default withRouter(Header)
//withRouter可以加工一般组件,让一般组件具备路由组件所特有的API
//withRouter的返回值是一个新组件
三、通用Hooks
使用在5.1版本及之后,并且是函数式组件中才可以使用,使用见第四点传参时候的代码演示
(一)useHistory
获取History对象。访问history对象,进行编程式的导航
//导入
import {useHistory } from "react-router-dom"
const Home = () => {
return (
Home
)
}
const Detail = () => {//使用
const history = useHistory()
console.log("history",history);//获取History对象
console.log("获取当前页路径",history.location.pathname);//获取当前页路径
//和下面通过js获取一致
console.log(props.location.pathname);
return (
<-- 使用--> <button onClick={() => { history.push('/')}}>go home</button> </div>
)
}
function App() {
return (
<Router>
<Switch>
<Route exact path="/" component={Home}/>
<Route path="/detail/:id" component={Detail}/>
</Switch>
</Router>
);
}(二)useLocation
获取Location对象。在各层组件中,轻松获取location对象。在V5.1版本之前,我们需要使用props.location。而对于更深层的组件,还需要使用
withRouter
//导入
import {
useLocation
} from "react-router-dom";
//使用
const location = useLocation () console.log("location",location);
(三)useParams
获取路由参数的键值对的对象,访问当前的<Route>的match.params。在V5.1版本之前,我们需要通过
props.match
获取路由参数。对于更深层的组件还需要使用高阶组件
withRouter
//设置<Route>的match.params
<Router>
<Switch>
<Route path="/:path">
<Home></Home>
</Route>
</Switch>
</Router>//获取
let { path } = useParams();
console.log("path ",path );
(四)useRouteMatch
useRouteMatch
,接受一个
path
字符串作为参数。当参数的
path
与当前的路径相匹配时,useRouteMatch会返回match对象,否则返回null。
useRouteMatch
在对于一些,不是路由级别的组件。但是组件自身的显隐却和当前路径相关的组件时,非常有用。
比如,你在做一个后台管理系统时,网页的Header只会在登录页显示,登录完成后不需要显示,这种场景下就可以用到
useRouteMatch
。
const Home = () => {
return (
Home
)
}
// Header组件只会在匹配/detail/:id
时出现
const Header = () => {
// 只有当前路径匹配/detail/:id
时,match不为null
const match = useRouteMatch('/detail/:id')
return (
match &&Header
)
}
const Detail = () => {
return (
Detail
)
}
function App() {
return (
<Router>
<Switch>
<Route exact path="/" component={Home}/>
<Route exact path="/detail/:id" component={Detail}/>
</Switch>
</Router>
);
}(五)useRoutes
路由表,钩子在
useRoutes
功能上等同于,但它里面使用
JavaScript 对象
而不是
<Route>
元素来定义您的路由
useRoutes()
的参数为数组。useRoutes
的返回值要么是可用于渲染路由树的有效 React 元素,要么null
是不匹配的元素。- 嵌套路由用 children 实现。
使用useRoutes实现:
import * as React from "react";
import { useRoutes } from "react-router-dom";function App() {
let element = useRoutes([
{
path: "/",
element: <Dashboard />,
children: [
{
path: "messages",
element: <DashboardMessages />,
},
{ path: "tasks", element: <DashboardTasks /> },
],
},
{ path: "team", element: <AboutPage /> },
]);return element;
}使用Routes和Route实现:
<Routes> <Route path="/" element={<Dashboard />}> <Route path="messages" element={<DashboardMessages />} /> <Route path="tasks" element={<DashboardTasks />} /> </Route> <Route path="about" element={<AboutPage />} /> </Routes>四、路由传参
在v5.x中只有编程式的获取参数方式,在v5.1及之后增加了Hooks后,既可以用编程式的方式获取url携带的参数,也可以使用Hooks中的方法来获取(只能是函数式组件),前面一种也成为显式传参,后面两种成为隐式传参
(一)params参数
1、注册路由
//注册路由
<Route path="/details/:name/:age" component={Details}/>2、路由跳转
//路由跳转
<Link to='/details/tom/18'}>详情</Link>或
<button onClick={()=>{props.history.push('details/tom/18')}}>去详情页</button>
3、在详情页获取参数
//在详情页获取参数
console.log(props.match.params);
或
import { useParams } from "react-router-dom";
const params = useParams();
(二)search参数
1、注册路由
//注册路由
<Route path="/details" component={Details}/>2、路由跳转
//路由跳转
<Link to='/details/tom/18'}>详情</Link>或
<button onClick={()=>{props.history.push('details?name=tom&age=18')}}>去详情页</button>
3、在详情页获取参数
//在详情页获取参数
console.log(props.location.search);//拿到的是?id=1&age=18,
或
import { useParams } from "react-router-dom";
const params = useParams();拿到的是?id=1&age=18
在以上两种方式中,获取到的search是urlencoded编码字符串,需要借助query-string解析参数成对象或者自己封装一个截取的工具函数
const { search } = props.location
const { num } = qs.parse(search.slice(1))
(三)state参数
1、注册路由
//注册路由
<Route path="/details" component={Details}/>2、路由跳转
//路由跳转
<Link to={{pathname:'/detils', state:{ id:1, age:18 }
}} > 去详情页 </Link>
或
<button onClick={()=>{props.history.push({
pathname:'/details', state:{ id:1, age:18 }
})}}>去详情页</button>
3、在详情页获取参数
//在详情页获取参数
console.log(props.history.location.state);//{id: 1, age: 18}
import { useLocation } from "react-router-dom";
const { state } = useLocation();
console.log(state);//{id: 1, age: 18}
版权归原作者 夏*想想 所有, 如有侵权,请联系我们删除。