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 App
app.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 HeaderDom
HeaderDom.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 LoadableDom
NavDom.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 NavDom
NavDom.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 NavDomList
SiderDom.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 SiderDom
MenuList.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 Home
home.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