React 實現炫酷的可拖拽網格佈局

Bilif發表於2019-05-14

前言

最近老闆讓做一個自定義皮膚,能夠在皮膚上自由的拖拽,新增,刪除元件。元件可以是各種echarts圖形,通過各個元件的拖拽組合,從而讓使用者自定義想要看到的皮膚。需求就是這樣,那麼擼起袖子開始幹!?

專案預覽

demo地址

QQ20190514-131658-HD-compress.gif
元件可以動態新增,刪除,可以自由拖拽,縮放。並且縮放後元件內部的echarts圖表也會跟著縮放。

專案實戰

技術架構
  1. 前端框架:React
  2. UI庫:Ant Design
  3. 腳手架:create-react-app
  4. 拖拽外掛:react-grid-layout
技術實現
  1. 使用npm安裝react-grid-layout包
npm install react-grid-layout
複製程式碼
  1. 在js檔案中引入WidthProvider和Responsive元件,並且例項化響應式拖拽元件。在css檔案中引入外掛的樣式。
import { WidthProvider, Responsive } from "react-grid-layout";
const ResponsiveReactGridLayout = WidthProvider(Responsive);
複製程式碼
@import '~react-grid-layout/css/styles.css';
@import '~react-resizable/css/styles.css';
複製程式碼
  1. 在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>
複製程式碼
  1. 通過generateDOM函式生成佈局中的元件,首先先遍歷元件陣列,通過每個元件的型別判斷生產柱狀圖元件,折線元件,還是餅圖元件。每個元件必須定義一個全域性唯一的key值。data-grid為每一個元件繫結了其屬性。下面會介紹具體的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>
      );
    });
  };
複製程式碼
  1. 通過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,
        }),
      },
    );
  };
複製程式碼
  1. 通過onRemoveItem函式來移除增元件。
onRemoveItem(i) {
    console.log(this.state.widgets)
    this.setState({
      widgets: this.state.widgets.filter((item,index) => index !=i)
    });

  }
複製程式碼

後記

感謝支援。若不足之處,歡迎大家指出,共勉。

如果覺得不錯,記得 點贊,謝謝大家 ?

原始碼地址

歡迎關注 我的:【Blog】【Github】【掘金】【簡書】

相關文章