【默默努力】react-drag-grid
先放项目地址:https://github.com/Bilif/react-drag-grid
项目运行效果
感谢无私开源的程序员
先看项目入口文件
//index.js
import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import App from './App';
import * as serviceWorker from './serviceWorker';
ReactDOM.render(<App />, 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-PWA
serviceWorker.unregister();
可以看到主要内容主要在App.js中
接下来我们来看App.js
//App.js
import React from 'react';
import './App.css';
import DragLayout from './DragLayout';
function App() {
return (
<DragLayout></DragLayout>
);
}
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:当响应式布局中的组件发生拖拽或者放大缩小时触发该函数。
<ResponsiveReactGridLayout
className="layout"
{...this.props}
layouts={this.state.layouts}
onLayoutChange={(layout, layouts) =>
this.onLayoutChange(layout, layouts)
}
>
{this.generateDOM()}
</ResponsiveReactGridLayout>
使用echarts-for-react插件可以在React中调用echarts接口直接渲染出Echarts图表,只要传入相关的参数和数据即可。
安装
npm install --save echarts-for-react]
npm install --save echarts
使用
let component = (
<ReactEcharts
option={option}
notMerge={true}
lazyUpdate={true}
style={{width: '100%',height:'100%'}}
/>
)
这边将三种图封装在了chart中
//chart.js
export 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} <br> 合格率: {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} <br/>{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 = (
<ReactEcharts
option={option}
notMerge={true}
lazyUpdate={true}
style={{width: '100%',height:'100%'}}
/>
)
return (
<div key={l.i} data-grid={l}>
<span className='remove' onClick={this.onRemoveItem.bind(this, i)}>x</span>
{component}
</div>
);
});
};
通过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全部代码为
//DragLayout
import 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 = (
<ReactEcharts
option={option}
notMerge={true}
lazyUpdate={true}
style={{width: '100%',height:'100%'}}
/>
)
return (
<div key={l.i} data-grid={l}>
<span className='remove' onClick={this.onRemoveItem.bind(this, i)}>x</span>
{component}
</div>
);
});
};
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(
<Layout>
<Header style={{ position: 'fixed', zIndex: 1, width: '100%','padding': '0 30px' }}>
<Button type="primary" style={{'marginRight':'7px'}} onClick={this.addChart.bind(this,'bar')}>添加柱状图</Button>
<Button type="primary" style={{'marginRight':'7px'}} onClick={this.addChart.bind(this,'line')}>添加折线图</Button>
<Button type="primary" style={{'marginRight':'7px'}} onClick={this.addChart.bind(this,'pie')}>添加饼图</Button>
</Header>
<Content style={{ marginTop: 44 }}>
<div style={{ background: '#fff', padding: 20, minHeight: 800 }}>
<ResponsiveReactGridLayout
className="layout"
{...this.props}
layouts={this.state.layouts}
onLayoutChange={(layout, layouts) =>
this.onLayoutChange(layout, layouts)
}
>
{this.generateDOM()}
</ResponsiveReactGridLayout>
</div>
</Content>
</Layout>
)}
}
部分讲解内容学习自博客:https://juejin.im/post/5cda5719e51d453a36384923
【默默努力】react-drag-grid的更多相关文章
- 2018.5.2(7:20到的办公室开始早课 阮一峰的JS) 所有的默默努力都是为了让自己看起来毫不费力
continue语句用于立即终止本轮循环,返回循环结构的头部,开始下一轮循环. break语句用于跳出代码块或循环. 标签(label) JavaScript 语言允许,语句的前面有标签(label) ...
- 【默默努力】PixelFire
先放下我玩游戏的效果图: 关于游戏最后的结束部分其实我还没有截图,看着挺好看的,后面的效果 再放作者大大的项目地址:https://github.com/panruiplay/PixelFire 接下 ...
- 【默默努力】fishingGame
这个捕鱼游戏挺有意思的,通过发射子弹,打鱼.打鱼的子弹会消耗金币,但是打鱼如果打到了鱼,就会奖励金币的数量. 我如果写这个的话,应该会画一个 背景海底,然后生成很多鱼的图片,还要有一个大炮,金币.大炮 ...
- 【默默努力】h5-game-heroVSmonster
先放下作者大大的项目地址:https://github.com/yangyunhe369/h5-game-heroVSmonster 然后游戏的效果为 截动图的按键与游戏按键应该冲突,我就截几张图片了 ...
- 【默默努力】h5-game-blockBreaker
先放下游戏的效果,我不太会玩游戏 然后放下无私开源的作者大大的地址:https://github.com/yangyunhe369/h5-game-blockBreaker 这个游戏的话,我觉得应该是 ...
- 【默默努力】ig-wxz-and-hotdog
这个是一个非常跟热点的小游戏,思聪吃热狗.这个游戏的话,我感觉思路还挺简单的,天上会掉热狗和障碍物, 思聪在下面张开嘴巴,进行左右移动,接热狗.如果吃到的是热狗就得一分,如果思聪吃到的不是热狗,是障碍 ...
- 【默默努力】vue-pc-app
最近在github上面看到了一个团队的项目,真的非常赞.他们进行vue-cli的二次开发,将项目用自己的方式打包. 今天的这个开源项目地址为:https://github.com/tffe-team/ ...
- 【招聘App】—— React/Nodejs/MongoDB全栈项目:信息完善&用户列表
前言:最近在学习Redux+react+Router+Nodejs全栈开发高级课程,这里对实践过程作个记录,方便自己和大家翻阅.最终成果github地址:https://github.com/66We ...
- react-native聊天室|RN版聊天App仿微信实例|RN仿微信界面
一.前言 9月,又到开学的季节.为每个一直默默努力的自己点赞!最近都沉浸在react native原生app开发中,之前也有使用vue/react/angular等技术开发过聊天室项目,另外还使用RN ...
随机推荐
- iOS 点击Application icon加载推送通知Data
今天做APNS远程推送通知遇到了一个问题,就是手机接收到通知的时候,如果马上点击通知的 alert view时候,系统马上唤醒你的Application,通知或调用你的didReceiveLocalN ...
- STM32F103
memory map • Four masters: – Cortex® -M3 core DCode bus (D-bus) and System bus (S-bus)– GP-DMA1 & ...
- LightOJ-1282-Leading and Trailing-快速幂+数学
You are given two integers: n and k, your task is to find the most significant three digits, and lea ...
- 学习笔记——CDQ分治
再次感谢这位大佬的博客:https://www.cnblogs.com/ljc20020730/p/10395866.html CDQ分治,是一种在分治合并中计算前面值对后面答案的贡献的一种算法.今天 ...
- Round Numbers /// 组合计数 oj21455
题目大意: 给定a,b 输出[a,b]的闭区间中round number的数量 所谓round就是一个数在二进制下0的个数大于等于1的个数 0的个数>=1的个数 也就是1的个数<=0的个数 ...
- [转]Visual Studio 各版本下载
原文地址:[置顶] Visual Studio 各版本下载 文件名称 文件大小 百度网盘下载 微软官方下载 Visual Studio 2015 Enterprise - 企业版 - 简体中文 3.8 ...
- 继承内部类时使用外部类对象.super()调用内部类的构造方法
问题简介 今天在看<Java编程思想>的时候,看到了一个很特殊的语法,懵逼了半天--一个派生类继承自一个内部类,想要创建这个派生类的对象,首先得创建其父类的对象,也就是这个内部类,而调 ...
- Yii2 在php 7.2环境下运行,提示 Cannot use ‘Object’ as class name
出错原因是: Object是php7.2中的保留类名,不可以使用Object作为类的名称. The object name was previously soft-reserved in PHP 7. ...
- [转]SpringMVC框架入门配置 IDEA下搭建Maven项目
初衷:本人初学SpringMVC的时候遇到各种稀奇古怪的问题,网上各种技术论坛上的帖子又参差不齐,难以一步到位达到配置好的效果,这里我将我配置的总结写到这里供大家初学SpringMVC的同僚们共同学习 ...
- Java 集群高可用监控(结合阿里SLB)脚本
欢迎点评,大家一起来优化 计划思路: 只有在mysql slave java 进程状态都正常的情况下才允许nginx 运行, 否则就干掉它, 负载用的是阿里的SLB #bin/bash #邮件函数 ...