先放项目地址:
项目运行效果 感谢无私开源的程序员 先看项目入口文件//index.jsimport React from 'react';import ReactDOM from 'react-dom';import './index.css';import App from './App';import * as serviceWorker from './serviceWorker';ReactDOM.render(, document.getElementById('root'));// If you want your app to work offline and load faster, you can change// unregister() to register() below. Note this comes with some pitfalls.// Learn more about service workers: https://bit.ly/CRA-PWAserviceWorker.unregister();
可以看到主要内容主要在App.js中
接下来我们来看App.js//App.jsimport React from 'react';import './App.css';import DragLayout from './DragLayout';function App() { return ();}export default App;
我们可以看到App中主要引用的是DragLayout组件
也就是核心功能点在DragLayout组件中 在DragLayout中我们会看到引用了一些组件 比如antd,用来布局以及样式 react-grid-layout是一个好用的拖拽、自适应布局 react 插件 它的使用方法为import { WidthProvider, Responsive } from "react-grid-layout";const ResponsiveReactGridLayout = WidthProvider(Responsive);
在React的render方法中渲染可拖拽布局。ResponsiveReactGridLayout组件有多个属性。
cols:定义了响应式布局划分成几列。 rowHeight:响应式布局中组件的行高。 onLayoutChange:当响应式布局中的组件发生拖拽或者放大缩小时触发该函数。this.onLayoutChange(layout, layouts) } > {this.generateDOM()}
使用echarts-for-react插件可以在React中调用echarts接口直接渲染出Echarts图表,只要传入相关的参数和数据即可。
安装npm install --save echarts-for-react]npm install --save echarts
使用
let component = ()
这边将三种图封装在了chart中
//chart.jsexport function getBarChart() { const option = { tooltip: { trigger: 'axis', axisPointer: { // 坐标轴指示器,坐标轴触发有效 type: 'shadow' // 默认为直线,可选为:'line' | 'shadow' } }, grid: { left: '3%', right: '4%', bottom: '3%', containLabel: true }, xAxis: [{ type: 'category', data: ['2014', '2015', '2016', '2017', '2018', '2019'], axisLine:{ lineStyle:{ color:'#8FA3B7',//y轴颜色 } }, axisLabel: { show: true, textStyle: { color: '#6D6D6D', } }, axisTick: {show: false} }], yAxis: [{ type: 'value', splitLine:{show: false}, //max: 700, splitNumber: 3, axisTick: {show: false}, axisLine:{ lineStyle:{ color:'#8FA3B7',//y轴颜色 } }, axisLabel: { show: true, textStyle: { color: '#6D6D6D', } }, }], series: [ { name: 'a', type: 'bar', barWidth: '40%', itemStyle: { normal: { color: '#FAD610' } }, stack: '信息', data: [320, 132, 101, 134, 90, 30] }, { name: 'b', type: 'bar', itemStyle: { normal: { color: '#27ECCE' } }, stack: '信息', data: [220, 182, 191, 234, 290, 230] }, { name: 'c', type: 'bar', itemStyle: { normal: { color: '#4DB3F5' } }, stack: '信息', data: [150, 132, 201, 154, 90, 130] } ] }; return option;}export function getLineChart() { //option const option = { color: ['#D53A35'], tooltip: { trigger: 'axis', //formatter: "{b} 合格率: {c}%" }, grid: { left: '3%', right: '4%', bottom: '3%', containLabel: true }, xAxis: { type: 'category', name: '', boundaryGap: false, axisLine:{ show:false, lineStyle:{ color:'#525252' } }, axisTick:{ show:false }, axisLabel:{ color:'#525252' }, data: ['01', '02', '03', '04', '05', '06', '07','08','09','10','11','12','13','14','15','16','17','18','19','20','21','22','23','24'] }, yAxis: { type: 'value', name: '', axisLine:{ show:false, }, axisTick:{ show:false }, axisLabel:{ color:'#525252' }, splitLine:{ lineStyle:{ type:'dotted', color:'#AAA'//F3F3F3 } } }, series: [{ name: 'a', type: 'line', symbol: 'circle', data: [100,120, 132, 101, 134, 90, 230, 210,80,20,90,210,200,100,120, 132, 101, 134, 90, 230, 210,80,20,90] } ] }; return option;}export function getPieChart() { //option const option = { color: ['#3AA1FF', '#36CBCB', '#4ECB73', '#FBD338'], tooltip: { trigger: 'item', formatter: '{a} {b}: {c} ({d}%)' }, grid: { left: '3%', right: '4%', bottom: '3%', containLabel: true }, series: [{ name: '消费能力', type: 'pie', radius: ['40%', '55%'], center: ['50%', '55%'], avoidLabelOverlap: true, itemStyle: { normal: { borderColor: '#FFFFFF', borderWidth: 2 } }, label: { normal: { show: false, }, }, labelLine: { normal: { show: false } }, data: [{ name: 'a', value: '20' }, { name: 'b', value: '40' }, { name: 'c', value: '10' }, { name: 'd', value: '10' }] }] }; return option;}
通过generateDOM函数生成布局中的组件,首先先遍历组件数组,通过每个组件的类型判断生产柱状图组件,
折线组件,还是饼图组件。每个组件必须定义一个全局唯一的key值。data-grid为每一个组件绑定了其属性。generateDOM = () => { return _.map(this.state.widgets, (l, i) => { let option; if (l.type === 'bar') { option = getBarChart(); }else if (l.type === 'line') { option = getLineChart(); }else if (l.type === 'pie') { option = getPieChart(); } let component = () return ( x {component}); }); };
通过addItem函数来新增组件。
每个组件属性如下:x: 组件在x轴坐标
y: 组件在y轴坐标 w: 组件宽度 h: 组件高度 i: 组件key值addItem(type,widgetId) { const addItem = { x: (this.state.widgets.length * 2) % (this.state.cols || 12), y: Infinity, // puts it at the bottom w: 2, h: 2, i: widgetId || new Date().getTime().toString(), }; this.setState( { widgets: this.state.widgets.concat({ ...addItem, type, }), }, ); };
通过onRemoveItem函数来移除增组件。
onRemoveItem(i) { console.log(this.state.widgets) this.setState({ widgets: this.state.widgets.filter((item,index) => index !=i) }); }
DragLayout.js全部代码为
//DragLayoutimport React, { PureComponent } from 'react';import { Layout,Button } from 'antd';import { WidthProvider, Responsive } from "react-grid-layout";import _ from "lodash";import ReactEcharts from 'echarts-for-react';import { getBarChart,getLineChart,getPieChart } from "./chart";const ResponsiveReactGridLayout = WidthProvider(Responsive);const { Header, Content} = Layout;export default class DragLayout extends PureComponent { static defaultProps = { cols: { lg: 12, md: 10, sm: 6, xs: 4, xxs: 2 }, rowHeight: 100, }; constructor(props) { super(props); this.state = { layouts: this.getFromLS("layouts") || {}, widgets:[] } } getFromLS(key) { let ls = {}; if (global.localStorage) { try { ls = JSON.parse(global.localStorage.getItem("rgl-8")) || {}; } catch (e) { /*Ignore*/ } } return ls[key]; } saveToLS(key, value) { if (global.localStorage) { global.localStorage.setItem( "rgl-8", JSON.stringify({ [key]: value }) ); } } generateDOM = () => { return _.map(this.state.widgets, (l, i) => { let option; if (l.type === 'bar') { option = getBarChart(); }else if (l.type === 'line') { option = getLineChart(); }else if (l.type === 'pie') { option = getPieChart(); } let component = () return ( x {component}); }); }; addChart(type) { const addItem = { x: (this.state.widgets.length * 3) % (this.state.cols || 12), y: Infinity, // puts it at the bottom w: 3, h: 2, i: new Date().getTime().toString(), }; this.setState( { widgets: this.state.widgets.concat({ ...addItem, type, }), }, ); }; onRemoveItem(i) { console.log(this.state.widgets) this.setState({ widgets: this.state.widgets.filter((item,index) => index !=i) }); } onLayoutChange(layout, layouts) { this.saveToLS("layouts", layouts); this.setState({ layouts }); } render() { return()}} this.onLayoutChange(layout, layouts) } > {this.generateDOM()}
部分讲解内容学习自博客: