antd + react-grid-layout 所见即所得

先安装 react-grid-layout
npm install react-grid-layout

首先从服务器去拿数据,是否有保存的面板方案,如果没有就使用默认面板(可以自己保存默认面板方案),默认面板方案也是从服务器获取,取到数据之后渲染
我没有把单个面板写活,只是暂时对每个面板定了一个唯一的i

i----是指面板的名称
h—是面板的高度
w—是面板的宽度
x—是面板的坐标 x轴
y—是面板的坐标 y轴
这些是react-grid-layout渲染所需要的值

第一步:取数据–保存到state中的widgets 中

 //从服务器获取所有面板列表
  getFromService = () => {
    const { dispatch, user } = this.props;
    const { widgets } = this.state;
    if (user.currentUser.username)
      dispatch({
        type: "dragShow/findPritOverViewLayoutByPublic",
        payload: {
          "pageNum": 1,//页码  必填
          "pageSize": 20,//数量  必填
          "owner": user//所属人(新建入)  非必填
        },
        callback: res => {
          if (res && res.resultCode === 200 && res.data) {
            this.setState({ modeList: res.data.list }, () => {
              this.setDefaultModel();
            });
          }
        }
      })
  }
  //获取默认模板,并渲染
  setDefaultModel = () => {
    const { modeList } = this.state;
    if (modeList.length === 1) {
      //只有一条数据,是默认公共模板,公共模板不可删除
      this.changeModeList(modeList[0].layoutId);
    } else if (modeList.length > 1) {
      const defaultModel = modeList.find(item => item.isDefault === 1);
      defaultModel ?
        this.changeModeList(defaultModel.layoutId) :
        this.changeModeList(modeList[0].layoutId);
    }
  }
  //选择方案模型列表中的一个,赋值到react-grid-layout渲染所需要的值
  changeModeList = (value) => {
    const { modeList } = this.state;
    const {
      form: { setFieldsValue }
    } = this.props;
    const current = modeList.find(item => item.layoutId === value);
    // 面板
    const currentArr = [];
    const iscurShowArr = [];
    if (current && current.contentJson) {
      current.contentJson.map(item => {
        let obj = {};
        obj.i = item.widgetId;
        obj.h = Number(item.height);
        obj.w = Number(item.width);
        obj.x = Number(item.xaxis);
        obj.y = Number(item.yaxis);
        iscurShowArr.push(item.widgetId.split('-')[1]);
        currentArr.push(obj);
      })
      setFieldsValue({ modelName: current.name })
      setFieldsValue({ modellist: current.layoutId })
      this.setState({ widgets: currentArr, isShowArr: iscurShowArr, editLayoutId: current.layoutId })
    }
  }

第二步:渲染

引入
import { Responsive, WidthProvider } from 'react-grid-layout';
const ResponsiveGridLayout = WidthProvider(Responsive);
//需要引入css 不然 缩放的那个小图标出不来,还有一些其他问题
import 'react-grid-layout/css/styles.css'
import 'react-resizable/css/styles.css'

  //需要注意 面板发生变化的时候,需要实时保存数据到widgets中
  onLayoutChange = (current, layouts) => {
    // console.log(current);
    let EUlayoutArr = [];
    var index = -1;
    current.forEach(({ i, x, y, w, h }) => {
      index++;
      EUlayoutArr[index] = { i, x, y, w, h };
    })
    this.setState({ widgets: EUlayoutArr });
  }
  //---渲染
  setPanelShow = () => {
    const { widgets, obj } = this.state;
    return _.map(widgets, (l, i) => {
      let component = obj[l.i.split("-")[1]];
      return (
        <div className='drag' key={l.i} data-grid={l} style={{ background: '#222A39' }}>
          <div className="deleteTag" onClick={() => this.onRemoveItem(l.i)}>×</div>
          <div className="dragcontent">
            {component}
          </div>
        </div>
      )
    })
  }
  
//render里面的代码
              {/* 交易员和基金经理区分模块显示 */}
              <ResponsiveGridLayout className="layout" layouts={{ lg: widgets }} rowHeight={30}
                breakpoints={{ lg: 768, md: 768, sm: 768, xs: 768, xxs: 0 }}
                cols={{ lg: 12, md: 12, sm: 12, xs: 12, xxs: 12 }}
                isResizable={true} //设置可缩放
                onLayoutChange={(layout, layouts) => this.onLayoutChange(layout, layouts)}
                margin={[10, 10]}
                isDraggable={true} //设置可拖动
                measureBeforeMount={false}
                useCSSTransforms={true}
                // onBreakpointChange={this.onBreakpointChange}
                preventCollision={!this.state.compactType}
              >
                {this.setPanelShow()}
              </ResponsiveGridLayout>

左侧是一栏放小面板的管理列, 点击可以添加到右侧的容器里,右侧容器可以拖拽缩放
左侧点击添加的代码(判断数组是否有这个面板,如果没有则不显示,写法较挫):


  //左侧显示面板-----方法
  isShowComponent = (mode, type) => {
    const { isShowArr, obj } = this.state;
    return (isShowArr.find(item => item === type) ? "" : <div className="leftItem" onClick={() => this.addMoudle(mode, type)}>{obj[type]}</div>)
  }
//----render里面的代码
          <Col span={4} style={{ paddingRight: 10 }}>
            <div className="leftbox" >
              {this.isShowComponent('tz', 'portfolioTable')}
              {this.isShowComponent('tz', 'trendChart')}
              {this.isShowComponent('tz', 'redemptionChart')}
              {this.isShowComponent('tz', 'keyChart')}
              {this.isShowComponent('tz', 'mainCard')}
              {this.isShowComponent('tz', 'tradeTodayChart')}
              {this.isShowComponent('tz', 'noticeTable')}
              {this.isShowComponent('tz', 'assetsChart')}
            </div>
          </Col>

搞懂了渲染机制,那么保存和删除就容易很多了,
全部代码:


import React, { Component } from 'react';
import { connect } from 'dva';
import { Responsive, WidthProvider } from 'react-grid-layout';
import _ from "lodash";
//单个面板,我这有8个面板
import PortfolioTable from './component/portfolioTable'
import NoticeTable from './component/noticeTable'

import TrendChart from './component/trendChart'
import RedemptionChart from './component/redemptionChart'
import KeyChart from './component/keyChart'
import TradeTodayChart from './component/tradeTodayChart'
import AssetsChart from './component/assetsChart'

import MainCard from './component/mainCard'

import { Row, Col, Form, Button, Input, message, Select, Popconfirm, Checkbox } from 'antd';

import styles from './index.less'
import 'react-grid-layout/css/styles.css'
import 'react-resizable/css/styles.css'

const { Option } = Select;

const ResponsiveGridLayout = WidthProvider(Responsive);

@connect(({ user }) => ({ user }))
@Form.create()
class DragShow extends Component {
  constructor(props) {
    super(props);
    this.state = {
      isEUorCP: 'CP',
      newConters: 0,
      compactType: "vertical",
      // layouts: { lg: props.initialLayout },
      // layouts: this.getFromLS('layouts'),
      widgets: [],
      obj: {
        "portfolioTable": <PortfolioTable />,
        "noticeTable": <NoticeTable />,
        "trendChart": <TrendChart />,
        "redemptionChart": <RedemptionChart />,
        "keyChart": <KeyChart />,
        "mainCard": <MainCard />,
        "tradeTodayChart": <TradeTodayChart />,
        "assetsChart": <AssetsChart />
      },
      isShowArr: [],
      modeList: [],
      editLayoutId: "",
    }
  }

  UNSAFE_componentWillMount() {

  };

  componentWillUnmount() {
    // componentWillMount进行异步操作时且在callback中进行了setState操作时,需要在组件卸载时清除state
    this.setState = () => {
      return;
    };
  }

  componentDidMount() {
    const { user: userMc } = this.props;
    //获取方案模板列表
    if (userMc) {
      this.getFromLS()
    }
  }

  componentDidUpdate(prevProps) {
    const { user: userMc } = this.props;
    const { user } = prevProps;
    if (user !== userMc) {
      this.getFromLS()
    }
  }

  //从服务器获取所有面板列表
  getFromService = () => {
    const { dispatch, user } = this.props;
    const { widgets } = this.state;
    if (user.currentUser.username)
      dispatch({
        type: "dragShow/findPritOverViewLayoutByPublic",
        payload: {
          "pageNum": 1,//页码  必填
          "pageSize": 20,//数量  必填
          // "name":"string",//面板名称    非必填
          "owner": user.currentUser.username//所属人(新建入)  非必填
        },
        callback: res => {
          if (res && res.resultCode === 200 && res.data) {
            this.setState({ modeList: res.data.list }, () => {
              this.setDefaultModel();
            });

          }
        }
      })
  }

  //存储拖拽移动的位置到缓存
  onLayoutChange = (current, layouts) => {
    // console.log(current);
    let EUlayoutArr = [];
    var index = -1;
    current.forEach(({ i, x, y, w, h }) => {
      index++;
      EUlayoutArr[index] = { i, x, y, w, h };
    })
    this.setState({ widgets: EUlayoutArr });
  }

  //获取默认模板,并渲染
  setDefaultModel = () => {
    const { modeList } = this.state;
    if (modeList.length === 1) {
      //只有一条数据,是默认公共模板,公共模板不可删除
      this.changeModeList(modeList[0].layoutId);
      // setFieldsValue({modellist:modeList[0].layoutId})
    } else if (modeList.length > 1) {
      const defaultModel = modeList.find(item => item.isDefault === 1);
      defaultModel ?
        this.changeModeList(defaultModel.layoutId) :
        this.changeModeList(modeList[0].layoutId);
    }
  }

  // 删除项目
  onRemoveItem(i) {
    //i  项目-面板
    const { widgets, isShowArr } = this.state;
    this.setState({
      //面板过滤掉 删除项目,以及左侧内容过滤
      widgets: widgets.filter(item => item.i !== i), isShowArr: isShowArr.filter(item => { return item !== i.split('-')[1] })
    })
    localStorage.setItem('layouts', JSON.stringify(widgets))
  }


  //添加单个面板
  addMoudle = (mode, type) => {
    const { newConters, widgets, isShowArr } = this.state;
    const addItem = {
      i: `${mode}-${type}`,
      x: 0,
      y: 0,
      w: 6,
      h: 8,
    }
    isShowArr.push(type)
    widgets.push(addItem)
    this.setState({
      widgets, newConters: newConters + 1, isShowArr: [...new Set(isShowArr)]
    })
  }

  //初始化时,加载左侧面板
  setPanelShow = () => {
    const { widgets, obj } = this.state;
    return _.map(widgets, (l, i) => {
      let component = obj[l.i.split("-")[1]];
      return (
        <div className='drag' key={l.i} data-grid={l} style={{ background: '#222A39' }}>
          <div className="deleteTag" onClick={() => this.onRemoveItem(l.i)}>×</div>
          <div className="dragcontent">
            {component}
          </div>
        </div>
      )
    })
  }

  //左侧显示面板
  isShowComponent = (mode, type) => {
    const { isShowArr, obj } = this.state;
    return (isShowArr.find(item => item === type) ? "" : <div className="leftItem" onClick={() => this.addMoudle(mode, type)}>{obj[type]}</div>)
  }

  // 输入方案模型名称
  onChangeModelName = (value) => {
  }

  //保存方案模板
  onSave = () => {
    const { dispatch, user, form: { getFieldValue } } = this.props;
    const { widgets, editLayoutId, modeList,isdefalutCheck } = this.state;
    if (!getFieldValue("modelName")) {
      message.error("请先输入面板名称");
      return false;
    }
    if (modeList.find(item => item.name === getFieldValue("modelName")) && editLayoutId === "") {
      message.error("该面板已存在,请修改面板名称");
      return false;
    }
    const currentModel = modeList.find(item => item.layoutId === editLayoutId);
    if (currentModel && currentModel.layoutShortCode === "public") {
      message.error('不能修改公共默认模板,请知悉')
      return false;
    }
    const contentJson = [];
    widgets.map(item => {
      const obj = {};
      obj.widgetId = item.i;
      obj.height = item.h;
      obj.width = item.w;
      obj.xaxis = item.x;
      obj.yaxis = item.y;
      contentJson.push(obj);
    })
    let payload = {
      "contentJson": contentJson,
      "owner": user.currentUser.username,
      "name": getFieldValue("modelName"),
      "layoutId": editLayoutId,
      "isDefault":isdefalutCheck?1:0
    }
    const typeurl = editLayoutId ? "dragShow/editPritOverViewLayout" : "dragShow/addPritOverViewLayout";
    dispatch({
      type: typeurl,
      payload: payload,
      callback: res => {
        if (res && res.resultCode === 200) {
          message.success(res.resultMsg)
        } else {
          message.error(res.resultMsg)
        }
      }
    })
  }

  //重置
  onReset = () => {
    const { form: { setFieldsValue } } = this.props;
    setFieldsValue({ modelName: "",modellist:"" });
    this.setState({ editLayoutId: "",isdefalutCheck:false });
  }

  //选择方案模型列表中的一个,渲染
  changeModeList = (value) => {
    const { modeList } = this.state;
    const {
      form: { setFieldsValue }
    } = this.props;
    const current = modeList.find(item => item.layoutId === value);
    // 面板
    const currentArr = [];
    const iscurShowArr = [];
    if (current && current.contentJson) {
      current.contentJson.map(item => {
        let obj = {};
        obj.i = item.widgetId;
        obj.h = Number(item.height);
        obj.w = Number(item.width);
        obj.x = Number(item.xaxis);
        obj.y = Number(item.yaxis);
        iscurShowArr.push(item.widgetId.split('-')[1]);
        currentArr.push(obj);
      })
      setFieldsValue({ modelName: current.name })
      setFieldsValue({ modellist: current.layoutId })
      this.setState({ widgets: currentArr, isShowArr: iscurShowArr, editLayoutId: current.layoutId })
    }
  }

  //删除一个模板
  delPritOverViewLayout = () => {
    const { dispatch, user } = this.props;
    const { editLayoutId, modeList } = this.state;
    const currentModel = modeList.find(item => item.layoutId === editLayoutId);
    if (currentModel && currentModel.layoutShortCode === "public") {
      message.error('不能删除公共默认模板,请知悉')
      return false;
    }
    if (user.currentUser.username) {
      dispatch({
        type: "dragShow/delPritOverViewLayout",
        payload: {
          "layoutId": editLayoutId,
          "owner": user.currentUser.username//所属人(新建入)  非必填
        },
        callback: res => {
          if (res && res.resultCode === 200) {
            message.success(res.resultMsg)
            this.setDefaultModel();
          } else {
            message.error(res.resultMsg)
          }
        }
      })
    }
  }

  //选中或者不选中是否为默认
  onChangeCheck = (e) => {
    this.setState({isdefalutCheck:e.target.checked})
  }

  render() {
    const { widgets, modeList, editLayoutId ,isdefalutCheck} = this.state;
    const {
      form: { getFieldDecorator }
    } = this.props;
    const options = modeList.map(item => <Option key={item.layoutId}>{item.name}</Option>)
    return (
      <div style={{ margin: 20 }} className={styles.dragShow}>
        <div className="tablebg" style={{ padding: 10, marginBottom: 10 }}>
          <div className="search-box">
            <Form layout="inline">
              <Form.Item label='面板列表'>
                {getFieldDecorator(`modellist`)(<Select style={{ width: '120px' }} onChange={this.changeModeList} >{options}</Select>)}
              </Form.Item>
              <Form.Item label='面板名称'>
                {getFieldDecorator(`modelName`)(<Input disabled={editLayoutId !== ""} style={{ width: '120px' }} onChange={this.onChangeModelName} />)}
              </Form.Item>
              <Checkbox checked = {isdefalutCheck} onChange={this.onChangeCheck}>设为默认面板</Checkbox>
              <Button style={{ marginTop: '3px', marginRight: 10 }} type='dashed' onClick={this.onSave}>保存</Button>
              <Button style={{ marginTop: '3px', marginRight: 10 }} className="greyButton" onClick={this.onReset}>重置</Button>
              {/* <Button style={{ marginTop: '3px', marginRight: 10 }} className='buleButton' onClick={this.onSave}>设为默认</Button> */}
              <Popconfirm title="确定删除该项吗?" onConfirm={() => this.delPritOverViewLayout()}>
                <Button style={{ marginTop: '3px', marginRight: 10 }} className="greyButton" >删除</Button>
              </Popconfirm>
            </Form>
          </div>
        </div>
        <Row>
          <Col span={4} style={{ paddingRight: 10 }}>
            <div className="leftbox" >
              {this.isShowComponent('tz', 'portfolioTable')}
              {this.isShowComponent('tz', 'trendChart')}
              {this.isShowComponent('tz', 'redemptionChart')}
              {this.isShowComponent('tz', 'keyChart')}
              {this.isShowComponent('tz', 'mainCard')}
              {this.isShowComponent('tz', 'tradeTodayChart')}
              {this.isShowComponent('tz', 'noticeTable')}
              {this.isShowComponent('tz', 'assetsChart')}
            </div>
          </Col>
          <Col span={20} style={{ paddingLeft: 10 }}>
            <div className="rightbox" >
              {/* 交易员和基金经理区分模块显示 */}
              <ResponsiveGridLayout className="layout" layouts={{ lg: widgets }} rowHeight={30}
                breakpoints={{ lg: 768, md: 768, sm: 768, xs: 768, xxs: 0 }}
                cols={{ lg: 12, md: 12, sm: 12, xs: 12, xxs: 12 }}
                isResizable={true}
                onLayoutChange={(layout, layouts) => this.onLayoutChange(layout, layouts)}
                margin={[10, 10]}
                isDraggable={true}
                measureBeforeMount={false}
                useCSSTransforms={true}
                // onBreakpointChange={this.onBreakpointChange}
                preventCollision={!this.state.compactType}
              >
                {this.setPanelShow()}
              </ResponsiveGridLayout>
            </div>
          </Col>
        </Row>
      </div>
    );
  }
}

export default DragShow;

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值