1.配置代理
yarn add http-proxy-middleware
在src下新建setupProxy.js
pathRewrite 会替换掉url中的api
const { createProxyMiddleware } = require('http-proxy-middleware');
module.exports = function (app) {
app.use(createProxyMiddleware('/api',
{
target: 'http://bkk3.com', //测试
changeOrigin: true,
pathRewrite: {
'^/api': ''
}
}
));
};后台返回,登录成功,跳转到app/home页
{"data":{"msg":"\u767b\u5f55\u6210\u529f","token":"1644657230uaDiO6nFtd5Rl8AJd41d8cd98f00"},"code":0}php代码
<?php
namespace app\api\controller;
use app\BaseController;
class Login extends BaseController
{
public function doSignIn()
{
$arr = [
'data'=>[
'msg'=>'登录成功',
'token'=>'1644657230uaDiO6nFtd5Rl8AJd41d8cd98f00'
],
'code'=>0
];
return $arr;
}
}2.调整主页内容
yarn add react-loadable
app.js
import React, { useState, useCallback } from 'react'
import { Route, Routes, HashRouter } from 'react-router-dom'
import { Layout } from 'antd';
import SiderDom from '../common/SiderDom/SiderDom'
import HeaderDom from '../common/HeaderDom/HeaderDom'
import loadable from '../common/Loadable/Loadable';
import NavDom from '../common/NavDom/NavDom';
import './app.less'
const { Content } = Layout;
// 异步加载组件,按需加载
const Home = loadable(() => import('pages/home/home'));
function App() {
const [collapsed, setCollapsed] = useState(false)
const toggle = useCallback(() => {
setCollapsed(!collapsed)
});
return (
<div className="app">
<Layout className="app-layout">
<SiderDom collapsed={collapsed} />
<Layout className="site-layout">
<HeaderDom toggle={toggle} />
<NavDom />
<Content className="site-layout-content">
<HashRouter>
<Routes>
<Route path="/app/home" component={Home} />
</Routes>
</HashRouter>
</Content>
</Layout>
</Layout>
</div>
)
}
export default Appapp.less
.app{
height: 100%;
//组件自带样式
#components-layout-demo-custom-trigger .trigger {
padding: 0 24px;
font-size: 18px;
line-height: 64px;
cursor: pointer;
transition: color 0.3s;
}
#components-layout-demo-custom-trigger .trigger:hover {
color: #1890ff;
}
#components-layout-demo-custom-trigger .logo {
height: 32px;
margin: 16px;
background: rgba(255, 255, 255, 0.3);
}
.site-layout .site-layout-background {
background: #fff;
}
.ant-layout-sider{
background: none !important;
}
.ant-layout-sider-children{
height : calc(~"100% - 24px") !important;
box-shadow: 0px 0px 6px 0px rgba(0, 0, 0, 0.1);
background: #001529;
}
//自定义
.app-layout{
height:100%;
.site-layout{
.ant-layout-header{
height: 48px;
}
.site-layout-content{
background: #fff;
margin: 8px 24px 24px;
padding: 24px;
min-height: 280px;
box-shadow: 0px 0px 6px 0px rgba(0, 0, 0, 0.1);
}
}
}
}接着处理顶部导航,侧边菜单样式整理一下
HeaderDom.js
import React, { memo, useState } from 'react'
import { useNavigate } from "react-router-dom";
import { Layout, message } from 'antd';
import {
MenuUnfoldOutlined,
MenuFoldOutlined,
UserOutlined,
} from '@ant-design/icons';
import './HeaderDom.less'
const { Header } = Layout
const HeaderDom = memo(
function HeaderDom(props) {
const [optionsShow, setOptionShow] = useState('none')
let navigate = useNavigate();
//鼠标移入user
const userMouseover = () => {
setOptionShow('block')
}
//鼠标移出user
const userMouseout = () => {
setOptionShow('none')
}
//退出登陆
const loginOut = () => {
message.success('退出成功')
navigate('/')
}
return (
<div className="HeaderDom">
<Header className="site-layout-background" style={{ padding: 0 }}>
{React.createElement(props.collapsed ? MenuUnfoldOutlined : MenuFoldOutlined, {
className: 'trigger',
onClick: props.toggle,
})}
<div
className="user"
onMouseEnter={() => { userMouseover() }}
onMouseLeave={() => { userMouseout() }}
>
<UserOutlined />
<span>欢迎admin</span>
<div
className="optionsList"
style={{ display: optionsShow }}
>
<div className="optionsList-content">
<div className="optionsList-item" >个人信息</div>
<div className="optionsList-item" onClick={() => { loginOut() }}>退出登陆</div>
</div>
</div>
</div>
</Header>
</div>
)
}
)
export default HeaderDomHeaderDom.less
.HeaderDom {
height: 48px;
box-shadow: 0px 0px 6px 0px rgba(0, 0, 0, 0.1);
.trigger {
margin-left: 24px;
transform: translateY(-8px);
}
.user {
float: right;
height: 48px;
line-height: 48px;
display: inline-block;
margin-right: 24px;
cursor: pointer;
span {
margin-left: 8px;
}
.optionsList {
width: 120px;
text-align: center;
position: absolute;
top: 48px;
z-index: 99;
.optionsList-content{
margin-top: 8px;
box-shadow: 0px 0px 6px 0px rgba(0, 0, 0, 0.1);
.optionsList-item {
background-color: #fff;
height: 40px;
line-height: 40px;
// &:first-child {
// margin-top: 8px;
// }
}
}
.optionsList-item:hover {
background-color: #CCCCCC;
}
}
}
}loadable.js
import React from 'react'
import Loadable from 'react-loadable';
import { Spin } from 'antd';
function LoadableDom(loader) {
return Loadable({
loader,
loading() {
return <Spin tip="Loading..." />
},
})
}
export default LoadableDomNavDom.js
import React, { useEffect, useState } from 'react'
import { Breadcrumb } from 'antd';
import { Link } from 'react-router-dom'
import NavDomList from './NavDomList.js'
import './NavDom.less'
function NavDom() {
// console.log(window.location.hash)
const [navList, setNavList] = useState([])
useEffect(() => {
let navList = window.location.hash.split('/')
navList.splice(0, 2)
console.log(navList)
setNavList(navList)
}, [window.location.hash])
return (
<div className="NavDom">
<Breadcrumb>
<Breadcrumb.Item>
<Link to="/app/home">首页</Link>
</Breadcrumb.Item>
{
navList.map((item, index) => {
return (
<Breadcrumb.Item key={index}>
<Link to={NavDomList[item].url}>
{NavDomList[item].name}
</Link>
</Breadcrumb.Item>
)
})
}
{/*
<Breadcrumb.Item>
<a href="">Application Center</a>
</Breadcrumb.Item>
<Breadcrumb.Item>
<a href="">Application List</a>
</Breadcrumb.Item>
<Breadcrumb.Item>An Application</Breadcrumb.Item> */}
</Breadcrumb>
</div>
)
}
export default NavDomNavDom.less
.navDom{
margin-top: 8px;
margin-left: 24px;
}NavDomList.js
const NavDomList = {
'home': {
name: '',
url: ''
},
'article': {
name: '文章管理',
url: '/app/article/article'
},
'articleList': {
name: '文章管理',
url: '/app/article/article'
},
'categoryList': {
name: '分类管理',
url: '/app/category/category'
}
}
export default NavDomListSiderDom.js
import React, { memo, useState, useEffect } from 'react'
import { Layout } from 'antd';
import { Menu } from 'antd';
import { Link } from 'react-router-dom'
import MenuList from './MenuList.js'
const { Sider } = Layout;
const { SubMenu } = Menu;
function SiderDom(props) {
const [selectedKeys, setSelectedKeys] = useState(['home'])
const [openKeys, setOpenKeys] = useState(['home'])
const { collapsed } = props
const MenuOnOpenChange = (openKeys) => {
let newOpenKeys = openKeys.pop()
setOpenKeys([newOpenKeys])
}
const MenuOnSelect = (e) => {
setSelectedKeys([e.key])
}
useEffect(() => {
let url = window.location.hash
let urlList = url.split('/')
setOpenKeys([urlList[2]])
setSelectedKeys([urlList[3]])
}, [window.location.hash])
return (
<Sider trigger={null} collapsible collapsed={collapsed}>
<Menu
selectedKeys={selectedKeys}
openKeys={openKeys}
mode="inline"
theme="dark"
onOpenChange={(openKeys) => MenuOnOpenChange(openKeys)}
onSelect={(e) => MenuOnSelect(e)}
>
{MenuList.map(item => {
if (item.children) {
return (
<SubMenu
key={item.key}
icon={item.icon}
title={item.name}
>
{
item.children.map(item => (
<Menu.Item key={item.key}>
<Link to={item.content}>{item.name}</Link>
</Menu.Item>
))
}
</SubMenu>
)
}
else {
return (
<Menu.Item key={item.key} icon={item.icon}>
<Link to={item.content}>{item.name}</Link>
</Menu.Item>
)
}
})}
</Menu>
</Sider>
)
}
export default SiderDomMenuList.js
import {
HomeOutlined,
UserOutlined,
ShopOutlined,
CarryOutOutlined,
} from '@ant-design/icons';
const MenuList = [
{
key: "home",
name: "首页",
content: "/app/home",
icon: < HomeOutlined />,
children: null
},
{
key: "article",
name: "文章",
icon: < ShopOutlined />,
children: [
{
key: "articleList",
name: "文章管理",
content: "/app/article/article",
},
{
key: "categoryList",
name: "分类管理",
content: "/app/category/category",
}
]
}
]
export default MenuList接着正文
home.js
import React, { useState, useEffect } from 'react'
import { Row, Col, Card } from 'antd';
import RequestTools from 'utils/request.js'
import {
UserOutlined,
MenuOutlined,
CheckSquareOutlined,
} from '@ant-design/icons';
import './home.less'
const _req = new RequestTools()
function Home() {
const [data, setData] = useState({})
useEffect(() => {
_req.axiosPost({}, 'getBasicData').then(res => {
console.log(res)
setData(res.data)
})
}, [])
return (
<div className='home'>
<Row gutter={24}>
<Col span={8} className="home-col">
<Card
className="card"
title={
<span className="card-title">
<UserOutlined className="card-icon" />
<span className="card-titleText">用户总数</span>
</span>
}
>
{data.userCount}
</Card>
</Col>
<Col span={8} className="home-col">
<Card
className="card"
title={
<span className="card-title">
<MenuOutlined className="card-icon" />
<span className="card-titleText">商品总数</span>
</span>
}
>
{data.productCount}
</Card>
</Col>
<Col span={8} className="home-col">
<Card
className="card"
title={
<span className="card-title">
<CheckSquareOutlined className="card-icon" />
<span className="card-titleText">订单总数</span>
</span>
}
>
{data.orderCount}
</Card>
</Col>
</Row>
</div>
)
}
export default Homehome.less
.home{
.home-col{
.card{
height: 200px;
width: 100%;
font-size: 30px;
}
.card-title{
.card-icon{
color: rgba(0,0,0,.45);
}
.card-titleText{
margin-left: 8px;
color: rgba(0,0,0,.45);
}
}
}
}最终目录为

运行一下 登录以后 空白页
react-router-dom的问题,路由使用了v5的写法导致的
修改几个地方
第一 router.js
import React from 'react'
import { HashRouter, Routes, Route } from 'react-router-dom'
import Login from 'pages/login/login'
import AppPage from 'pages/app/app'
import Home from 'pages/home/home'
function RouterDom() {
return (
<HashRouter>
<Routes>
<Route path="/" element={<Login/>} />
<Route path="/app/*" element={<AppPage/>} >
<Route path="home" element={<Home/>} />
</Route>
</Routes>
</HashRouter>
);
}
export default RouterDom第二个pages下的app.js
<Content className="site-layout-content"> <Outlet /> </Content>
第三个api.js增加个接口
getBasicData: `${HISTORY}/index/getBasicData`,返回数据
{"data":{"userCount":100,"productCount":120,"orderCount":140},"code":0}下一篇实现增删改查
本文为看恩吧原创文章,转载无需和我联系,但请注明来自knsay.com