【二】从零搭建react-新-实现登录接口和后台首页

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);
      }
    }
  }
}


最终目录为

image.png


运行一下 登录以后 空白页 

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}

下一篇实现增删改查

打赏

看恩吧
网站不承担任何有关评论的责任
  • 最新评论
  • 总共条评论
取消

感谢您的支持,我会继续努力的!

扫码支持
扫码打赏,你说多少就多少

打开支付宝扫一扫,即可进行扫码打赏哦