前言
最近老闆讓做一個自定義皮膚,能夠在皮膚上自由的拖拽,新增,刪除元件。元件可以是各種echarts圖形,通過各個元件的拖拽組合,從而讓使用者自定義想要看到的皮膚。需求就是這樣,那麼擼起袖子開始幹!?
專案預覽
![QQ20190514-131658-HD-compress.gif](https://i.iter01.com/images/89c41475a48150c6d1f557970b5bf9f65e6477073863b602b48be97190f05bfa.gif)
專案實戰
技術架構
- 前端框架:React
- UI庫:Ant Design
- 腳手架:create-react-app
- 拖拽外掛:react-grid-layout
技術實現
- 使用npm安裝react-grid-layout包
npm install react-grid-layout
複製程式碼
- 在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';
複製程式碼
- 在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>
複製程式碼
- 通過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>
);
});
};
複製程式碼
- 通過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)
});
}
複製程式碼
後記
感謝支援。若不足之處,歡迎大家指出,共勉。
如果覺得不錯,記得 點贊,謝謝大家 ?