前言:以下內容基於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" 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最大好處:將回調函數的異步調用變成鏈式調用
- 函數返回的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; } }
注:項目來自慕課網