• 【共享单车】—— 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;
                  }
              }  

    注:项目来自慕课网  

  • 相关阅读:
    低调 、隐忍、善良应是最应该修炼的
    达内C++培训课程
    这三天低效率开发的总结,我都做了些什么啊?
    linux sysfs(1)
    编码问题
    Linux中的system函数的实现和解释
    北京邮电大学 程序设计课程设计 电梯 文件输入版本(已调试,大致正确运行==)
    "Dallas" CTP3 发布通告
    结合使用PowerPivot 和 "Dallas" CTP3
    Windows Azure 解决方案系列: 能源监测减少支出,通过托管平台拓展业务
  • 原文地址:https://www.cnblogs.com/ljq66/p/10188214.html
Copyright © 2020-2023  润新知