共享单车—— React后台管理系统开发手记:主页面架构设计
Posted ljq66
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了共享单车—— 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(四则运算):运算符前后都需要保留一个空格
width: 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{ width: 15%; min-width: 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)
- AntD Menu组件:官方文档
- 更改主题色: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>
- 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" /> <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最大好处:将回调函数的异步调用变成链式调用
- 函数返回的Promise对象参数接受一个函数
- 参数1为成功的resolve回调函数
- 参数2是失败的reject回调函数函数体中返回对应函数调用
- 调用该返回Promise对象的函数的then方法
- 参数:以resolve函数传入的属性值为参数的函数
- 在方法体内写入回调成功返回的内容
- Header->index.js:
- 利用setInterval函数实时刷新时间信息,并调用utils包中的formate方法格式化时间戳
- 调用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> ) } }
- 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() } } - 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实现箭头图标
-
注意:当内部元素使用绝对定位,父级需要使用相对定位,否则内部元素则会相对整个文档进行绝对定位
-
after伪类:元素后添加内容实现箭头图标
-
实现下三角样式:设定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; } }
注:项目来自慕课网
以上是关于共享单车—— React后台管理系统开发手记:主页面架构设计的主要内容,如果未能解决你的问题,请参考以下文章
共享单车—— React后台管理系统开发手记:Redux集成开发
共享单车—— React后台管理系统开发手记:城市管理和订单管理
共享单车—— React后台管理系统开发手记:AntD Form基础组件
共享单车—— React后台管理系统开发手记:AntD Table高级表格