ChenxiiCheng / Notes

🌱 整理的学习笔记 | Notes + Tools
1 stars 0 forks source link

快速搭建 React 后台管理系统 (React + React-router-dom + Less + antd) #1

Open ChenxiiCheng opened 4 years ago

ChenxiiCheng commented 4 years ago

步骤:

(1) 配置 less

//1.yarn add less less-loader

//2.yarn eject   把webpack配置文件暴露出来
抛出这个问题:
? Are you sure you want to eject? This action is permanent. Yes
This git repository has untracked files or uncommitted changes:

解决办法:
git add .
git commit -am "Save before ejecting"

//3.在config/webpack.config.js文件中
const cssRegex = /\.css$/;
const cssModuleRegex = /\.module\.css$/;
const sassRegex = /\.(scss|sass)$/;
const sassModuleRegex = /\.module\.(scss|sass)$/;
const lessRegex = /\.less$/;                        //新增
const lessModuleRegex = /\.module\.less$/;          //新增

//4.在sass后面新增下面代码(其实是把上面sass的代码拿过来小改下)
{
  test: lessRegex,
    exclude: lessModuleRegex,
      use: getStyleLoaders(
        {
          importLoaders: 2,
          sourceMap: isEnvProduction && shouldUseSourceMap
        },
        'less-loader'
      ),
        // Don't consider CSS imports dead code even if the
        // containing package claims to have no side effects.
        // Remove this when webpack adds a warning or an error for this.
        // See https://github.com/webpack/webpack/issues/6571
        sideEffects: true
},
  // Adds support for CSS Modules, but using SASS
  // using the extension .module.scss or .module.sass
  {
    test: lessModuleRegex,
      use: getStyleLoaders(
        {
          importLoaders: 2,
          sourceMap: isEnvProduction && shouldUseSourceMap,
          modules: true,
          getLocalIdent: getCSSModuleLocalIdent
        },
        'less-loader'
      )
  },

(2) 配置antd

//1.yarn add antd   安装antd

//2.安装完成后引入组件,引入相关样式
import { Button } from 'antd'
import 'antd/dist/antd.css'

//3.yarn add babel-plugin-import  安装这个库为了实现按需加载的功能,即项目中用到什么样的组件,就引入对应的css

//4.在package.json文件中(注意不是暴露出的webpack文件)中相应位置配置:
  "babel": {
    "presets": [
      "react-app"
    ],
    "plugins": [
        // 如果使用了 定制颜色功能 将 "css" => true 同时需要配置 less
      // ["import", { "libraryName": "antd-mobile", "style": "css" }]
      [
        "import",
        {
          "libraryName": "antd",
          "style": true
        }
      ]
    ]
  }

//5.配置了babel-plugin-import后就不需要再引入import 'antd/dist/antd.css这句代码了,配置文件将自动引用相关antd的样式,从less文件转成css样式,作为行内样式插入元素中。重启项目,如果发生错误,检查less版本,发现是:"less": "^3.9.0",如果大于3.0版本,重新安装less并且版本小于3.0.0 -> yarn add less@2.7.3,重启项目 yarn start,成功加载了按钮样式

(3) Admin页面 【整个页面布局:左侧边栏NavLeft + 右侧分为Header + Content + Footer】

// {this.props.children} 是在router.js中
// <Admin>
// <Route path="/home" component={Home}    
//根据不同的url传给传不同组件去替换{this.props.children}
//</Admin>
import React, { Component } from 'react';
import NavLeft from './components/NavLeft';
import Header from './components/Header';
import Footer from './components/Footer';
import { Row, Col } from 'antd';
import './style/common.less';

class Admin extends Component {
  render() {
    return (
      <Row className="container">            
        <Col span={4} className="nav-left">
          <NavLeft />                           // 左侧边栏
        </Col>
        <Col span={20} className="main">
          <Header />                            // 头部
          <Row className="content">{this.props.children}</Row>   // 内容区
          <Footer />                            // 尾部
        </Col>
      </Row>
    );
  }
}

export default Admin;

(4) NavLeft组件

//menuList.js  想要显示的菜单栏
const menuList = [
  {
    title: '首页',
    key: '/home'
  },
  {
    title: 'UI',
    key: '/ui',
    children: [
      {
        title: '按钮',
        key: '/ui/button'
      },
      {
        title: '弹框',
        key: '/ui/modals'
      },
      {
        title: 'Loading',
        key: '/ui/loadings'
      },
      {
        title: '通知消息',
        key: '/ui/notification'
      },
      {
        title: '图片画廊',
        key: '/ui/gallery'
      },
      {
        title: '轮播图',
        key: '/ui/carousel'
      }
    ]
  },
  {
    title: '表单',
    key: '/form',
    children: [
      {
        title: '登录',
        key: '/form/login'
      },
      {
        title: '注册',
        key: '/form/register'
      }
    ]
  },
  {
    title: '表格',
    key: '/table'
  },
  {
    title: '富文本',
    key: '/rich'
  },
  {
    title: '城市管理',
    key: '/city'
  },
  {
    title: '订单管理',
    key: '/order'
  },
  {
    title: '员工管理',
    key: '/user'
  },
  {
    title: '统计分析',
    key: '/echarts',
    children: [
      {
        title: '柱形图',
        key: '/chart/bar'
      },
      {
        title: '饼图',
        key: '/chart/pie'
      },
      {
        title: '折线图',
        key: '/chart/line'
      }
    ]
  }
];

export default menuList;
// NavLeft/index.js
import React, { Component, Fragment } from 'react';
import { NavLink } from 'react-router-dom';
import MenuConfig from './../../resource/menuList';
import { Menu } from 'antd';
import './index.less';

const { SubMenu } = Menu;

class NavLeft extends Component {
  state = {
    currentKey: ''
  };

  componentWillMount() {
    const menuTreeNode = this.renderMenu(MenuConfig);
    let currentKey = window.location.hash.replace('/#|?.*$/g', '');
    this.setState({
      currentKey,
      menuTreeNode
    });
  }

  handleClick = ({ key }) => {
    this.setState({
      currentKey: key
    });
  };

  // 菜单渲染
  renderMenu = data => {
    return data.map(item => {
      if (item.children) {
        return (
          <SubMenu title={item.title} key={item.key}>
            {this.renderMenu(item.children)}
          </SubMenu>
        );
      }
      return (
        <Menu.Item title={item.title} key={item.key}>
          <NavLink to={item.key}>{item.title}</NavLink>
        </Menu.Item>
      );
    });
  };

  render() {
    return (
      <Fragment>
        <div className="logo">
          <img src="/assets/logo-ant.svg" alt="" />
          <h1>后台管理系统</h1>
        </div>
        <Menu
          selectedKeys={this.state.currentKey}
          theme="dark"
          onClick={this.handleClick}
        >
          {this.state.menuTreeNode}
        </Menu>
      </Fragment>
    );
  }
}

export default NavLeft;

//index.less
.nav-left .logo {
  padding-left: 20px;
  line-height: 90px;
  background: #002140;
  img {
    height: 35px;
    vertical-align: middle;
  }
  h1 {
    display: inline-block;
    margin: 0 0 0 10px;
    vertical-align: middle;
    color: #ffffff;
    font-size: 20px;
  }
}

(5) Header组件

import React, { Component } from 'react';
import { Row, Col } from 'antd';
import './index.less';

class Header extends Component {
  componentWillMount() {
    this.setState({
      userName: 'Chenxi'
    });
  }

  render() {
    return (
      <div className="header">
        <Row className="header-top">
          <Col span={24}>
            <span>欢迎,{this.state.userName}</span>
            <a href="#">退出</a>
          </Col>
        </Row>
      </div>
    );
  }
}

export default Header;

// index.less
.header {
  background: #ffffff;
  box-shadow: 0 1px 3px rgba(26, 26, 26, 0.1);
  .header-top {
    padding: 0 20px;
    height: 60px;
    line-height: 60px;
    text-align: right;
  }
  a {
    margin-left: 20px;
  }
}

(6) Footer组件

import React, { Component } from 'react';
import './index.less';

class Footer extends Component {
  render() {
    return (
      <div className="footer">
        版权所有:Chenxii(推荐使用Google Chrome,可以获得更佳操作体验)
        技术支持:Chenxii
      </div>
    );
  }
}

export default Footer;

//index.less
.footer {
  height: 100px;
  padding: 40px 0;
  text-align: center;
  color: #d7d7d7;
}

(7) 随便先写两个页面,用于router中配置跳转

Home

import React, { Component } from 'react';
import './index.less';

export default class Home extends Component {
  render() {
    return <div className="home-wrap">欢饮来到小白单车后台管理系统</div>;
  }
}

//index.less
.home-wrap {
  display: flex;
  align-items: center;
  justify-content: center;
  height: 500px;
  font-size: 20px;
  background: #ffffff;
  box-shadow: 0 1px 3px rgba(26, 26, 26, 0.1);
}

Login

import React, { Component } from 'react';

export default class Login extends Component {
  render() {
    return (
      <div>
        <h1>This is login page!!</h1>
      </div>
    );
  }
}

(8) 路由的配置

//1. yarn add react-router-dom

//2.写router.js文件
import React, { Component } from 'react';
import { HashRouter, Route, Switch } from 'react-router-dom';
import App from './App';
import Admin from './admin';
import Login from './pages/Login';
import Home from './pages/Home';

class Router extends Component {
  render() {
    return (
      <HashRouter>
        <App>
          <Switch>
            <Route path="/login" component={Login} />
            <Route
              path="/"
              render={() => (
                <Admin>
                  <Route path="/home" component={Home} />
                </Admin>
              )}
            />
          </Switch>
        </App>
      </HashRouter>
    );
  }
}
export default Router;

效果图

ChenxiiCheng commented 4 years ago
react-admin-1
ChenxiiCheng commented 4 years ago
react-admin-2
ChenxiiCheng commented 4 years ago
react-admin-3