编码式导航:基于JavaScript实现路由的跳转。
编码式导航:基于JavaScript实现路由的跳转。实际上是基于props中history对象中的相关方法实现路由跳转的。
在路由当中:
在react-router-dom的V5版本中:
如果是受控组件,则路由内容,会给每个组件传递三个属性:
history 提供了路由跳转的方式。
跳转路由
与新增历史记录
。跳转路由
与替换当前的历史记录
。历史记录中指定位置
。location:记录当前路由的信息。
match:记录当前路由匹配的规则与匹配记录。
如果是非受控组件,默认不会传递这三个属性。
基于路由内部提供的withRouter()高阶组件
,把非受控组件
变为受控组件
。
非受控组件
,也具备这三个属性信息,可适用于任何类型的组件
。import { withRouter } from "react-router-dom";
const CommonMenu = function CommonMenu(props) {
console.log(`CommonMenu-props`, props);
return
}
export default withRouter(CommonMenu);
基于路由提供的useHistory()
/useLocation()
/useParams()
/useRouteMatch()
等Hook函数,在函数组件中获取对应的信息!
useHistory()
-> history对象
。useLocation()
-> location对象
。useRouteMatch()
-> match对象
。useParams()
-> 获取基于路径传参的信息。HashRouter()
/BrowserRouter()
等Router的内部!基于问号传参
传递信息。
URL地址栏
中可以看见(明文)。
丑
、不安全
、有长度限制
。urlencoded格式字符串
,接收的时候也需要处理这样的字符串。
qs库
或者new URLSearchParams()
处理。跳转后的目标组件
进行刷新操作
,因为传递的信息
在地址栏中有,所以依然可以获取问号传参信息
。基于隐式传参
传递信息。
传递的信息
在URL地址栏
中看不见。
不丑
、安全
、没有长度限制
。跳转后的目标组件
进行刷新操作
,因为地址栏
中没有传递的信息
,那么之前传递的信息
就消失了。基于路径参数
传递信息,把传参信息
作为地址的一部分
。
问号传参
一样,也是要把传递的信息
放在URL地址栏
中,所以相关特点和问号传参几乎一致。
问号传参
美观一些。path: '/home/message'
旧写法。path: '/home/message/:lx?/:name?'
新写法。
:
说明是传递的参数。?
可传可不传。match.params
/useParams()
处理即可!默认情况下,我们会把所有组件的代码全部打包到一个js文件中-即主js文件。这样当页面第一次渲染的时候,需要从服务器获取这个主js文件才能执行,但是因为其文件过大,需要加载很长时间,在此期间内,页面呈现白屏。
路由懒加载步骤:
在jsx文件及js代码中,使用src引入文件如图片这类需要使用文件地址时,要先用ES6把相对路径的文件导入进来再引用。或者使用绝对路径。
在css或less时,使用图片这类需要使用文件地址时,是可以直接使用相对路径的。
React阶段/day0603_router6/src/index.jsx
import React from "react";
import ReactDOM from "react-dom/client";
/* ANTD */
import { ConfigProvider } from "antd";
import zhCN from "antd/locale/zh_CN";
/* 组件&样式 */
import "./index.less";
import App from "./App";
const root = ReactDOM.createRoot(document.getElementById("root"));
root.render(
);
React阶段/day0603_router6/src/App.jsx 主视图文件,构建一级路由。
import React from "react";
// 1. 引入HashRouter, Routes, Route, Navigate等react-router-dom提供的组件。引入HashRouter用于把组件包起来,Routes用于设置路由信息组-把多条路由信息组合成一组以便只渲染一个路由视图,Route用于设置单条路由信息,Navigate用于与Route配合起来设置重定向。
import { HashRouter, Routes, Route, Navigate } from "react-router-dom";
// 2. 引入路由需要用到的业务视图组件。
import BasicLayout from "./layout/BasicLayout";
import UserLayout from "./layout/UserLayout";
import Error from "./layout/Error";
import Login from "./views/Login";
import Register from "./views/Register";
import Home from "./views/Home";
import Personal from "./views/Personal";
import Category from "./views/Category";
import Watch from "./views/home/Watch";
import Worker from "./views/home/Worker";
import Message from "./views/home/Message";
const App = function App() {
// 3. 构建路由。
return (
}>
} />
}>
} />
} />
} />
} />
} />
} />
}>
} />
} />
} />
} />
} />
);
};
export default App;
React阶段/day0603_router6/src/layout
React阶段/day0603_router6/src/layout/BasicLayout.jsx 一级路由组件。
import { useState } from "react"
import { Menu, Button } from "antd"
import { HomeOutlined, ClusterOutlined, UserOutlined, MenuUnfoldOutlined, MenuFoldOutlined } from '@ant-design/icons'
import styled from "styled-components"
import logo from "@/assets/images/logo.svg"
import avatar from "@/assets/images/touxiang.png"
import { Outlet } from "react-router-dom"
/* 组件样式 */
const BasicLayoutStyle = styled.div`
height: 100%;
overflow: hidden;
.header{
box-sizing: border-box;
padding: 0 15px;
height: 48px;
background: #001529;
display: flex;
justify-content: space-between;
align-items: center;
.logo,
.info{
line-height: 48px;
font-size: 18px;
color: #FFF;
display: flex;
align-items: center;
img{
margin-right: 10px;
width: 35px;
height: 35px;
}
}
.info{
font-size: 14px;
img{
width: 30px;
height: 30px;
}
}
}
.content{
height: calc(100% - 48px);
display: flex;
.menu-box{
height: 100%;
background: #001529;
.ant-btn{
margin-left: 4px;
background: transparent;
box-shadow: none;
}
.ant-menu-item{
padding: 0 24px;
}
.ant-menu-inline-collapsed{
.ant-menu-item{
padding: 0 28px;
}
}
}
.view-box{
box-sizing: border-box;
padding: 15px;
height: 100%;
flex-grow: 1;
.component{
height: 100%;
overflow-y: auto;
overflow-x: hidden;
background: #FFF;
}
}
}
`
const BasicLayout = function BasicLayout() {
// 左侧Menu的数据
const menuItem = [{
key: 'home',
label: '控制面板',
icon:
}, {
key: 'category',
label: '分类管理',
icon:
}, {
key: 'personal',
label: '个人中心',
icon:
}]
// 定义状态
let [collapsed, setCollapsed] = useState(false)
return
Ant Design
海贼王-路飞
{/* 主页的二级路由 */}
}
export default BasicLayout
React阶段/day0603_router6/src/layout/Error.jsx 一级路由组件。
import React from "react";
import { Button, Empty } from "antd";
import styled from "styled-components";
/* 组件的样式 */
const ErrorStyle = styled.div`
height: 100%;
overflow: hidden;
.ant-empty {
position: relative;
top: 100px;
}
`;
const Error = function Error() {
return (
很遗憾,您访问的页面不存在!}>
);
};
export default Error;
React阶段/day0603_router6/src/layout/UserLayout.jsx 一级路由组件。
import React from "react";
import { Tabs } from "antd";
import styled from "styled-components";
import backgroundImg from "@/assets/images/background.svg";
import logo from "@/assets/images/logo.svg";
import { Outlet } from "react-router-dom";
/* 组件样式 */
const UserLayoutStyle = styled.div`
position: relative;
height: 100%;
background: url(${backgroundImg}) no-repeat;
background-size: 100%;
.content {
position: absolute;
top: 100px;
left: 50%;
margin-left: -165px;
width: 330px;
}
.header {
.title {
display: flex;
justify-content: center;
align-items: center;
line-height: 44px;
font-size: 33px;
font-weight: normal;
img {
margin-right: 10px;
width: 44px;
height: 44px;
}
}
.subtitle {
margin: 12px 0 40px 0;
text-align: center;
font-size: 14px;
color: rgba(0, 0, 0, 0.45);
}
}
.ant-tabs {
margin-bottom: 10px;
.ant-tabs-nav {
&:before {
border-bottom-color: #ddd;
}
}
.ant-tabs-tab {
padding: 0 10px;
font-size: 16px;
line-height: 40px;
}
}
`;
const UserLayout = function UserLayout() {
// Tab页卡的数据
const tabItem = [
{
label: `用户登录`,
key: "login",
},
{
label: `用户注册`,
key: "register",
},
];
return (
Ant Design
Ant Design 是西湖区最具影响力的 Web 设计规范
{/* 登录/注册二级路由的位置 */}
);
};
export default UserLayout;
React阶段/day0603_router6/src/views 页面组件,一般是二级及以下的业务组件。
React阶段/day0603_router6/src/views/home 二级路由组件-Home.jsx下的三级路由组件。
React阶段/day0603_router6/src/views/home/Message.jsx
import React from "react";
const Message = function Message() {
return 控制面板 - 消息中心;
};
export default Message;
React阶段/day0603_router6/src/views/home/Watch.jsx
import React from "react";
const Watch = function Watch() {
return 控制面板 - 数据监控;
};
export default Watch;
React阶段/day0603_router6/src/views/home/Worker.jsx
import React from "react";
const Worker = function Worker() {
return 控制面板 - 工作台;
};
export default Worker;
React阶段/day0603_router6/src/views/Category.jsx
import React from "react";
const Category = function Category() {
return 分类管理的内容;
};
export default Category;
React阶段/day0603_router6/src/views/Home.jsx 二级路由组件。
import React from "react";
import styled from "styled-components";
import { NavLink, Outlet } from "react-router-dom";
/* 组件样式 */
const HomeStyle = styled.div`
padding: 10px;
.nav-box {
display: flex;
border-bottom: 1px solid #eee;
a {
padding: 0 20px;
line-height: 40px;
font-size: 15px;
color: #000;
&.active {
color: #1677ff;
font-size: 16px;
}
}
}
`;
const Home = function Home() {
return (
{/* 首页的三级路由 */}
);
};
export default Home;
React阶段/day0603_router6/src/views/Login.jsx 二级路由组件。
import React from "react";
import { Form, Input, Checkbox, Button } from "antd";
import { UserOutlined, LockOutlined } from "@ant-design/icons";
import styled from "styled-components";
/* 组件的样式 */
const LoginStyle = styled.div`
.remember {
display: flex;
justify-content: space-between;
align-items: center;
a {
font-size: 14px;
color: #1890ff;
}
}
.submit {
width: 100%;
}
`;
const Login = function Login() {
return (
}
/>
}
/>
记住账号密码
忘记密码?
);
};
export default Login;
React阶段/day0603_router6/src/views/Personal.jsx
import React from "react";
const Personal = function Personal() {
return 个人中心的内容;
};
export default Personal;
React阶段/day0603_router6/src/views/Register.jsx
import React from "react";
import { Form, Input, Button } from "antd";
import { LockOutlined, PhoneOutlined } from "@ant-design/icons";
import styled from "styled-components";
/* 组件的样式 */
const RegisterStyle = styled.div`
.submit {
width: 100%;
}
.code-box {
display: flex;
justify-content: space-between;
align-items: center;
.ant-form-item {
&:nth-child(1) {
margin-right: 10px;
}
}
}
`;
const Register = function Register() {
return (
}
/>
}
/>
);
};
export default Register;
在主视图文件里引入构建一级路由。
所有需要用到路由信息的,都要用这个组件包起来。
包裹一组路由信息。
标签
,放其它标签会报错。路由匹配规则
或路由表
都写在一起。
与
用来设置一条路由信息。
内部可以嵌套
与
。
默认匹配规则类似于
精准匹配。
被嵌套的
标签就是子级路由。
子级路由可以省略父级路由地址。
/
开头,就会被认为是绝对路径。/
开头,那么其前方就会自动添加上父级路由的地址。要渲染的组件用element属性来设置,但element属性的值必须是一个组件标签的格式,而不能只是一个函数变量。
} />//一个组件标签的格式,是对的。
//一个函数变量,是错的。
import React from "react";
// 1. 引入HashRouter, Routes, Route, Navigate等react-router-dom提供的组件。引入HashRouter用于把组件包起来,Routes用于设置路由信息组-把多条路由信息组合成一组以便只渲染一个路由视图,Route用于设置单条路由信息,Navigate用于与Route配合起来设置重定向。
import { HashRouter, Routes, Route, Navigate } from "react-router-dom";
// 2. 引入路由需要用到的业务视图组件。
import BasicLayout from "./layout/BasicLayout";
import UserLayout from "./layout/UserLayout";
import Error from "./layout/Error";
import Login from "./views/Login";
import Register from "./views/Register";
import Home from "./views/Home";
import Personal from "./views/Personal";
import Category from "./views/Category";
import Watch from "./views/home/Watch";
import Worker from "./views/home/Worker";
import Message from "./views/home/Message";
const App = function App() {
// 3. 构建路由。
return (
}>
} />
}>
} />
} />
} />
} />
} />
} />
}>
} />
} />
} />
} />
} />
);
};
export default App;
用于设置路由跳转。
在父级路由匹配组件的指定位置,基于
把子级路由匹配的内容进行渲染!
// 1. 引入Outlet组件。
import { Outlet } from "react-router-dom"
{/* 2. 在父级路由匹配组件的指定位置,基于` 组件`把子级路由匹配的内容进行渲染! */}
import { useState } from "react"
import { Menu, Button } from "antd"
import { HomeOutlined, ClusterOutlined, UserOutlined, MenuUnfoldOutlined, MenuFoldOutlined } from '@ant-design/icons'
import styled from "styled-components"
import logo from "@/assets/images/logo.svg"
import avatar from "@/assets/images/touxiang.png"
// 1. 引入Outlet组件。
import { Outlet } from "react-router-dom"
/* 组件样式 */
const BasicLayoutStyle = styled.div`
height: 100%;
overflow: hidden;
.header{
box-sizing: border-box;
padding: 0 15px;
height: 48px;
background: #001529;
display: flex;
justify-content: space-between;
align-items: center;
.logo,
.info{
line-height: 48px;
font-size: 18px;
color: #FFF;
display: flex;
align-items: center;
img{
margin-right: 10px;
width: 35px;
height: 35px;
}
}
.info{
font-size: 14px;
img{
width: 30px;
height: 30px;
}
}
}
.content{
height: calc(100% - 48px);
display: flex;
.menu-box{
height: 100%;
background: #001529;
.ant-btn{
margin-left: 4px;
background: transparent;
box-shadow: none;
}
.ant-menu-item{
padding: 0 24px;
}
.ant-menu-inline-collapsed{
.ant-menu-item{
padding: 0 28px;
}
}
}
.view-box{
box-sizing: border-box;
padding: 15px;
height: 100%;
flex-grow: 1;
.component{
height: 100%;
overflow-y: auto;
overflow-x: hidden;
background: #FFF;
}
}
}
`
const BasicLayout = function BasicLayout() {
// 左侧Menu的数据
const menuItem = [{
key: 'home',
label: '控制面板',
icon:
}, {
key: 'category',
label: '分类管理',
icon:
}, {
key: 'personal',
label: '个人中心',
icon:
}]
// 定义状态
let [collapsed, setCollapsed] = useState(false)
return
Ant Design
海贼王-路飞
{/* 主页的二级路由 */}
{/* 2. 在父级路由匹配组件的指定位置,基于` 组件`把子级路由匹配的内容进行渲染! */}
}
export default BasicLayout
react-router-dom(V6)
与react-router-dom(V5)
对比都是基于HashRouter()
与BrowserRouter()
来指定路由的模式,而且建议所有的组件都放在HashRouter()与BrowserRouter()这类Router
中。
V6版本中没有了
,因为不需要了,其内部自己做了类似于
的处理。
V6中没有了
,但是可以基于
来代替它。
相当于特殊的
,我们是基于它设置重定向的规则的。
是一个组件,渲染这个组件时会重定向到该组件的to属性指定的地址
。
} />
V6中也是基于
设置匹配规则,只不过都需要放在
上设置的详细规则,和V5版本有很大的区别:
上设置exact属性
用于进行精准匹配
了,因为默认都是类似于精准匹配
。
上path属性
和之前一样,设置对应的匹配地址。渲染那个组件
不再基于
上component属性
处理,而是基于
上element属性
渲染,而且也没有了
上render函数属性
这样的配置,element
渲染的内容需要写成
这种格式!
只能放
。
V5旧:
import { HashRouter, BrowserRouter, Route, Switch, Redirect } from 'react-router-dom'
import BasicLayout from "./layout/BasicLayout"
import UserLayout from "./layout/UserLayout"
import Error from "./layout/Error"
//或
V6新:
import { HashRouter, Routes, Route, Navigate } from "react-router-dom";
import BasicLayout from "./layout/BasicLayout";
import UserLayout from "./layout/UserLayout";
import Error from "./layout/Error";
}>
}>
} />
} />
//或
}>
V6有一个重大的变革:所有级别的路由匹配规则
或路由表
都写在一起,而不再像V5一样,需要分散到指定组件的特定位置
上,这样有利于路由的统一管理
!
}>
/* - 在`子级路由中`其path可以省略`父级路由的地址`
- 但是也不要自己再加`/`
- `path=""` 等价于 `path="/user"`
- `path="login"`等价于 `path="/user/login"`
- 如果路由地址是`/user/xxx`,首先和一级路由`/user`进行匹配了,渲染`UserLayout组件`后,进入`/user`的`子级路由`进行匹配;
- 在`子级路由`中`一项项地进行匹配`,匹配成功,就把`子级路由`中`element属性指定的组件`,放在`UserLayout组件`中的`容器`中进行渲染!
- 如果在`子级路由`中没有任何匹配的,则跳出这一级,继续向下匹配`与/user路由同级`的`其它的一级路由`! */
} />
} />
} />
在子级路由中
其path可以省略父级路由的地址
。
/
。path=""
等价于 path="/user"
。path="login"
等价于 path="/user/login"
。如果路由地址是/user/xxx
,首先和一级路由/user
进行匹配了,渲染UserLayout组件
后,进入/user
的子级路由
进行匹配;
子级路由
中一项项地进行匹配
,匹配成功,就把子级路由
中element属性指定的组件
,放在UserLayout组件
中的容器
中进行渲染!子级路由
中没有任何匹配的,则跳出这一级,继续向下匹配与/user路由同级
的其它的一级路由
!但是需要在上级路由匹配组件的指定位置,基于
把下级路由匹配的内容进行渲染!