zoukankan      html  css  js  c++  java
  • 【共享单车】—— React后台管理系统开发手记:主页面架构设计

    前言:以下内容基于React全家桶+AntD实战课程的学习实践过程记录。最终成果github地址:https://github.com/66Web/react-antd-manager,欢迎star。


     一、页面结构定义

    • 左侧导航栏,右侧页面结构
    • 右侧显示内容分别分为上Header、中Content和下Footer部分

    二、目录结构定义

    • src->admin.js:项目主结构代码(index.js中替换App.js挂载到根节点)
    • src->common.js:项目公共结构代码(类似admin.js,负责路由详情页展示)
    • src->components目录:项目公共组件
    • components->Footer、Header、NavLeft目录:index.js+index.less
    • src->pages目录:项目路由页面组件
    • src->style目录:全局样式common.less
    • src->config目录:菜单配置、项目其它变量配置
    • src->axios目录:执行axios请求文件 index.js
    • src->utils目录:项目工具方法
    • src->resource->assets目录:项目图片资源(public->assets目录供打包后使用)
    • src->resource->gellary目录:画廊图片资源(public->gellary目录供打包后使用)
    • src->resource->carousel-img目录:轮播图片资源(public->carousel-img目录供打包后使用)

    三、栅格系统使用

    • AntD栅格系统一共24列(BootStrap一共12列)
    • AntD中行用Row组件,列使用Col组件,列存在span属性(span={长度值}的方式写入span属性),同一Row下的Col span总和为24
      import { Row,Col } from 'antd'
      
      <Row>
           <Col span={4}>
                Left
           </Col>
           <Col span={20}>
                Right
           </Col>
      </Row>

    四、calc计算方法使用

    • calc()是less中动态计算长度值
    • calc(四则运算):运算符前后都需要保留一个空格
       calc(100% - 10px)//表示宽度属性是整个布局的100%减去50px的长度
    • calc(100vh):vh的含义相当于1%,100vh即是100%

    五、关于less

    • less是预编译器
    • 用法一:样式嵌套
      //css中
      div{...}
      div a{...}
      
      //less中
      div{
         ...
         a{
            ... 
         }
      }
    • 用法二:声明变量
      @colorA:'red'
      div{
         color:@colorA
         a{
            color:black 
         }
      } 

    六、架构代码

    • admin.js
      import React from 'react';
      import { Row, Col } from 'antd';
      import Header from './components/Header';
      import Footer from './components/Footer';
      import NavLeft from './components/NavLeft';
      import './style/common.less'
      class Admin extends React.Component{
        render(){
            return(
                <Row className="container">
                    <Col span={4} className="nav-left">
                        <NavLeft/>
                    </Col>
                    <Col span={20} className="main">
                        <Header/>
                        <Row className="content">
                            content
                        </Row>
                        <Footer/>
                    </Col>
                </Row>
            );
        }
      }
      export default Admin;
    • style->common.less

      .container{
        display: flex;
        .nav-left{
             15%;
            min- 180px;
            height: calc(100vh);
            background-color: red;
        }
        .main{
            flex: 1;
            height: calc(100vh);
        }
        .content{
            position: relative;
            padding: 20px;
        }
      }
    • components->Header/Footer/NavLeft->index.js

      import React from 'react';
      class Header extends React.Component{
        render(){
            return(
                <div>Header</div>
            )
        }
      }
      export default Header;

    七、导航栏内容

    • 在config下编写manuConfig.js返回导航栏内容title和key(AntD 路由地址)
      const menuList = [
          {
              title:'首页',
              key:'/admin/home'
          },
          {
              title:'UI',
              key:'/admin/ui',
              children:[
                  {
                      title:'按钮',
                      key:'/admin/ui/buttons',
                  },
                  {
                      title:'弹框',
                      key:'/admin/ui/modals',
                  },
                  {
                      title:'Loading',
                      key:'/admin/ui/loadings',
                  },
                  {
                      title:'通知提醒',
                      key:'/admin/ui/notification',
                  },
                  {
                      title:'全局Message',
                      key:'/admin/ui/messages',
                  },
                  {
                      title:'Tab页签',
                      key:'/admin/ui/tabs',
                  },
                  {
                      title:'图片画廊',
                      key:'/admin/ui/gallery',
                  },
                  {
                      title:'轮播图',
                      key:'/admin/ui/carousel',
                  }
              ]
          },
          {
              title:'表单',
              key:'/admin/form',
              children:[
                  {
                      title:'登录',
                      key:'/admin/form/login',
                  },
                  {
                      title:'注册',
                      key:'/admin/form/reg',
                  }
              ]
          },
          {
              title:'表格',
              key:'/admin/table',
              children:[
                  {
                      title:'基础表格',
                      key:'/admin/table/basic',
                  },
                  {
                      title:'高级表格',
                      key:'/admin/table/high',
                  }
              ]
          },
          {
              title:'富文本',
              key:'/admin/rich'
          },
          {
              title:'城市管理',
              key:'/admin/city'
          },
          {
              title:'订单管理',
              key:'/admin/order',
              btnList:[
                  {
                      title:'订单详情',
                      key:'/admin/order/detail'
                  },
                  {
                      title:'结束订单',
                      key:'/admin/order/finish'
                  }
              ]
          },
          {
              title:'员工管理',
              key:'/admin/user'
          },
          {
              title:'车辆地图',
              key:'/admin/bikeMap'
          },
          {
              title:'图标',
              key:'/admin/charts',
              children:[
                  {
                      title:'柱形图',
                      key:'/admin/charts/bar'
                  },
                  {
                      title:'饼图',
                      key:'/admin/charts/pie'
                  },
                  {
                      title:'折线图',
                      key:'/admin/charts/line'
                  },
              ]
          },
          {
              title:'权限设置',
              key:'/admin/permission'
          },
        ];
        export default menuList;  
    • 渲染菜单(Menu)
    1. AntD Menu组件:官方文档
    2. 更改主题色:theme属性  --  light/dark
      import { Menu, Icon } from 'antd';
      import MenuConfig from './../../config/manuConfig'
      
      const SubMenu = Menu.SubMenu;
      
      <Menu theme="dark">
                <SubMenu key="sub1" title={<span><Icon type="mail" /><span>Navigation One</span></span>}>
                      <Menu.Item key="1">Option 1</Menu.Item>
                      <Menu.Item key="2">Option 2</Menu.Item>
                      <Menu.Item key="3">Option 3</Menu.Item>
                       <Menu.Item key="4">Option 4</Menu.Item>
                </SubMenu>
      </Menu>  
    3. src->NevLeft->index.js :通过递归方法循环遍历manuConfig.js内容,渲染菜单
      import React from 'react'
      import { Menu, Icon } from 'antd';
      import MenuConfig from './../../config/manuConfig'
      import './index.less'
      
      const SubMenu = Menu.SubMenu;
      
      export default class NavLeft extends React.Component {
          componentWillMount() {
             const MenuTreeNode = this.renderMenu(MenuConfig);
             this.setState({
                 MenuTreeNode
             })
          }
          //菜单渲染 -- 递归
          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}>{item.title}</Menu.Item>
             })
          }
          render() {
              return (
                  <div>
                      <div className="logo">
                          <img src="/assets/logo-ant.svg" alt=""/>
                          <h1>LJQ MS</h1>
                      </div>
                      <Menu theme="dark">
                          {this.state.MenuTreeNode}      
                      </Menu>
                  </div>
              )
          }
      }
      

      NevLeft->index.less: 

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

    八、首页头部内容 

    • Axios不支持跨域,只支持Ajax相关get/post/put/delete请求
    • Jsonp支持跨域(所谓跨域就是跨域名,跨端口,跨协议)web页面上调用js文件时则不受跨域影响(且凡是有src属性的标签都具有跨域能力,如<script> <img> <iframe>等)
      yarn add jsonp --save
    • Promise最大好处:将回调函数的异步调用变成链式调用
    1. 函数返回的Promise对象参数接受一个函数
    2. 参数1为成功的resolve回调函数
    3. 参数2是失败的reject回调函数函数体中返回对应函数调用
    4. 调用该返回Promise对象的函数的then方法
    5. 参数:以resolve函数传入的属性值为参数的函数
    6. 在方法体内写入回调成功返回的内容
    • Header->index.js
    1. 利用setInterval函数实时刷新时间信息,并调用utils包中的formate方法格式化时间戳
    2. 调用axios包中的jsonp方法发送请求并根据promise进行回调
      import React from 'react'
      import { Row, Col } from 'antd'
      import './index.less'
      import Util from '../../utils/utils'
      import axios from '../../axios';
      
      export default class Header extends React.Component {
          state = {}
          componentWillMount() {
              this.setState({
                  userName: '莱茵月牙'
              })
              setInterval(() => {
                  let sysTime = Util.formateDate(new Date().getTime());
                  this.setState({
                      sysTime
                  })
              }, 1000)
              //this.getWeatherAPIDate();由于百度API禁止了服务,故该功能暂时不使用
          }
          getWeatherAPIDate() {
              let city = encodeURIComponent('杭州');
              axios.jsonp({
                  url: 'http://api.map.baidu.com/telematics/v3/weather?location='+city+'&output=json&ak=kwQXPVDYPZIYArkpi3rQT7aZHTGTCCB2'
              }).then((res) => {
                  if(res.status == 'success'){
                      let data = res.result[0].weather_data[0];
                      this.setState({
                          dayPictureUrl:data.dayPictureUrl,
                          weather:data.weather
                      })
                  } 
              })
          }
          render() {
              return (
                  <div className="header">
                     <Row className="header-top">
                        <Col span={24}>
                            <span>欢迎,{this.state.userName}</span>
                            <a href='#'>退出</a>
                        </Col>
                     </Row>
                     <Row className="breadcrumb">
                         <Col span={4} className="breadcrumb-title">
                            首页
                         </Col>
                         <Col span={20} className="weather">
                            <span className="date">{this.state.sysTime}</span>
                            <span className="weather-detail">晴转多云</span>
                         </Col>
                     </Row>
                  </div>
              )
          }
      }
      
    3. utils->utils.js
      export default {
          formateDate(time){
              if(!time)return '';
              let date = new Date(time);
              return date.getFullYear()+'-'+(date.getMonth()+1)+'-'+date.getDate()
      +' '+date.getHours()+':'+date.getMinutes()+':'+date.getSeconds() } }
    4. axios->index.js:使用JsonP模块发送请求获得jsonp数据,解决跨域问题
      import JsonP from 'jsonp'
      
      export default class Axios{
           static jsonp(options){
               new Promise((resolve, reject) => {
                   JsonP(options.url,{
                       param:'callback'
                   }, function (err, response) {
                      if(response.status === 'success'){
                          resolve(response);
                      }else{
                          reject(response.message);
                      }
                   })
               })
           }
      }  

    九、底部组件开发

    • Footer->index.js
      import React from 'react'
      import './index.less';
      
      export default class Footer extends React.Component {
          render() {
              return (
                  <div className="footer">
                      版权所有:柳洁琼Elena
                  </div>
              )
          }
      }  
    • less导入到其他less中 @import "文件路径";注意用@import引入,用分号分割】
    • less使用变量方式:@变量名
    • Footer->index.less
      @import "./../../style/default.less";
      
      .footer{
          height: 100px;
          padding: 40px 0;
          text-align: center;
          color: @colorJ;
      }
      

    十、Home页面实现

    • pages->Home->index.js
      import React from 'react'
      import './index.less'
      
      export default class Home extends React.Component{
          render() {
              return (
                  <div className="home-wrap">
                      欢迎学习慕课后台管理系统课程
                  </div>
              )
          }
      }
    • pages->Home->index.less

      @import './../../style/default.less';
      
      .home-wrap{
          background-color: @colorM;
          height: calc(62vh); //内容高度占右侧的62%
          display: flex;
          align-items: center;
          justify-content: center;
          font-size: 20px;
      }
      

      flex弹性布局:实现水平垂直居中

      display: flex;
      align-items: center;//前提布局是flex,align-items表示垂直居中
      justify-content: center;//前提布局是flex,align-items表示水平居中
      
    • CSS实现箭头图标

    1. 注意:当内部元素使用绝对定位,父级需要使用相对定位,否则内部元素则会相对整个文档进行绝对定位

    2. after伪类:元素后添加内容实现箭头图标

    3. 实现下三角样式:设定border-top为指定颜色,左右border为透明色(transparent)

       .breadcrumb{
              height: 40px;
              line-height: 40px;
              padding: 0 20px;
              border-top: 1px solid #f9c700;
              position: relative;   //父级元素相对定位
              .breadcrumb-title{
                  font-size: @fontC;
                  text-align: center;
                  &:after{
                      position: absolute;  //绝对定位
                      content: '';    //设为空用于占位
                      left: 73px;
                      top: 39px;
                      border-top: 9px solid @colorM;
                      border-left: 12px solid transparent;
                      border-right: 12px solid transparent;
                  }
              }  

    注:项目来自慕课网  

  • 相关阅读:
    POJ 3468 A Simple Problem with Integers
    BZOJ 4430 Guessing Camels
    POJ 2309 BST
    POJ 1990 MooFest
    cf 822B Crossword solving
    cf B. Black Square
    cf 828 A. Restaurant Tables
    Codefroces 822C Hacker, pack your bags!
    [HDU 2255] 奔小康赚大钱
    [BZOJ 1735] Muddy Fields
  • 原文地址:https://www.cnblogs.com/ljq66/p/10188214.html
Copyright © 2011-2022 走看看