該項目基於react-grid-layout
和antd
的柵格佈局實現。可能不適用全部項目, 可是思路也能夠參考。react
demo體驗地址: 自定義佈局git
源碼地址: 源碼github
經過可視化拖拽區塊, 組合區塊生成自定義佈局代碼, 可直接引入有antd的項目中使用。數組
上面可視化操做後生成的佈局代碼:antd
<Row>
<Col span={10} className="drag-item">
<Col className="drag-subitem" style={{ height: '10vh' }} span={24}></Col>
<Col className="drag-subitem" style={{ height: '95vh' }} span={24}></Col>
</Col>
<Col span={14} className="drag-item">
<Col className="drag-subitem" style={{ height: '25vh' }} span={24}></Col>
<Col className="drag-subitem" style={{ height: '80vh' }} span={24}></Col>
</Col>
</Row>
複製代碼
代碼生成的頁面:數據結構
要想生成任意佈局, 柵格佈局是最合適的。dom
這裏不考慮特殊狀況下的不規則佈局。工具
咱們先將佈局按列劃分, 每一列裏面再分紅幾塊, 這樣基本就能知足咱們大部分的業務場景了。佈局
提及來簡單,可是要和可視化拖拽結合起來就沒那麼簡單了。ui
咱們經過拖拽獲得每一個區塊的寬高和位置信息, 藉此來肯定咱們的區塊應該放在哪一個位置。
而後將其與antd的柵格佈局的API結合, 生成咱們想要的佈局代碼。
用過antd的柵格佈局的應該知道, Row控制行佈局, Col控制列布局。個人思路是:
整個頁面都是一個Row, 而後根據拖拽信息劃分列, 每一個列裏都是佔滿整個列寬的列, 這樣就能夠往下堆疊。
Col經過span
屬性控制寬度, 高度咱們直接經過style屬性加上去。
這裏不得不介紹一下強大的react-grid-layout
庫了。
git地址: react-grid-layout
咱們只須要提供簡單的基礎信息就能生成可拖拽可伸縮的區塊。 這裏對API不作過多介紹, 主要將實現。
const dragItem = { x: 14, y: 14, w: 1, h: 1, maxH: 20 }
<GridLayout className="layout"
onResizeStop={onResizeStop}
onDragStop={onDragStop}
preventCollision={true}
margin={[0, 0]}
cols={12}
rowHeight={30}
width={800}
style={{ height: 600 }}
>
{
Object.keys(dragObj).map(item => <div className="drag-item" style={{ backgroundColor: '#' + ('00000' + (Math.random() * 0x1000000 << 0).toString(16)).slice(-6) }} key={item} data-grid={dragObj[item]}></div>)
}
</GridLayout>
複製代碼
數據驅動視圖, 咱們經過添加區塊事件改變代碼中的dragObj, 便可實現往視圖中添加區塊。
當咱們改變了視圖中的區塊位置或大小時, 咱們須要保存當前的區塊信息, 方便咱們接下來的生成佈局代碼。
上面代碼中的onResizeStop
和onDragStop
事件能夠幫咱們監聽咱們的拖拽結束和改變區塊大小的動做。
這兩個事件作的事情是相同的, 記錄當前區塊狀態, 這裏看下事件代碼:
const onResizeStop = (arr) => {
let obj = {}, layoutObj = {}
arr.forEach(item => {
obj[item['i']] = { x: item['x'], y: item['y'], w: item['w'], h: item['h'], maxH: item['maxH'] }
if (layoutObj[item['x']]) {
layoutObj[item['x']].push(item)
} else {
layoutObj[item['x']] = [item]
}
})
setLayoutObj(layoutObj)
setDragObj(obj)
}
複製代碼
這兩個事件都會給咱們提供一個包含全部區塊信息的數組參數, 咱們經過對這個參數作解析, 將其改形成咱們可使用的數據結構, 並保存在state中。
當咱們經過拖拽生成咱們想要的數據結構後, 要生成咱們想要的頁面, 此時咱們須要知道, 區塊的位置和寬高如何映射到咱們的佈局中去。
我這裏經過約定: 拖拽區域大小爲寬800, 高600。 每一個區塊的基礎劃分:
將高度20等分, 寬度12等分。
這樣:
一個單位的h對應0.5vh的高度;
一個單位的w對應2個單位的span(antd的Col的span是24等分)
有了映射關係, 咱們只要把存儲區塊信息的對象改形成代碼串就好了:
const onCodeGenerator = () => {
setCodeStr(
'<Row>\n'
+
Object.keys(layoutObj).map(item => ` <Col span={${layoutObj[item][0].w * 2}} className="drag-item"> ${layoutObj[item].map(subItem => ` <Col className="drag-subitem" style={{height:'${subItem.h * 5}vh'}} span={24}></Col>\n`).join('')} </Col>\n`
).join('')
+
'</Row>'
)
}
複製代碼
經過上面的代碼進行改造, 就能獲得咱們想要的代碼串, 直接複製, 粘貼到咱們的項目中就獲得了一個合適的佈局。
這算是一個工具性的東西, 我是根據當前公司業務的基礎上進行的開發, 因此可能對你們的適用性不是很高, 這裏記錄下思路, 方便之後有相似的需求能夠參考。