輕松教你搞定組件的拖拽, 縮放, 多控制點伸縮和拖拽數(shù)據(jù)上報
也在 H5-Dooring 項目中做了很多技術(shù)實現(xiàn), 包括:
- 搭建平臺的組件設計和分類模式
- 拖拽生成頁面方案
- 動態(tài)表單編輯器設計
- 頁面實時預覽編譯技術(shù)
- 自定義組件和自定義模版方案
- 多人協(xié)作的可視化搭建模式實現(xiàn)
還有很多技術(shù)細節(jié)這里不一一舉例了, 最近在研究自由布局時發(fā)現(xiàn)有這樣一個需求, 我們可以自由拖拽和縮放組件, 并能從組件的不同緯度拖拽, 如下圖所示:

由于我們的技術(shù)棧采用的是 React, 目前還沒有一個成熟庫可以同時支持自由拖拽和縮放, 我們不得不用 react-dragable 和 react-resiable兩個庫來實現(xiàn)拖拽和縮放, 但是這樣我們要維護的數(shù)據(jù)結(jié)構(gòu)就相當復雜了(當然vue生態(tài)有成熟的vue-dragable等來支持自由拖拽和縮放), 所以最后筆者決定自己來實現(xiàn)一個.
我們從可視化搭建平臺的實際業(yè)務出發(fā), 可以分析出拖拽縮放有如下幾個功能點:
- 自由拖拽
- 支持控制點, 多方位縮放
- 支持自由控制層級
- 支持組件靜態(tài)化(即為了實現(xiàn)固定, 預覽頁面等效果)
- 拖拽縮放的數(shù)據(jù)能回傳給上層組件并提供受控機制
實現(xiàn)以上四點我們就可以實現(xiàn)一個可用的拖拽縮放組件. 接下來筆者就來介紹一下實現(xiàn)的開源拖拽縮放組件rc-drag.
實現(xiàn)自由拖拽
rc-drag未壓縮的體積只有20多k, 去除注釋核心代碼不到200行, 可以說是一個非常輕量的拖拽縮放組件庫了, 我們要想讓自己的組件能自由拖拽, 只需要使用如下方式:
1.安裝
- npm i @alex_xu/rc-drag
- # 或
- yarn add @alex_xu/rc-drag
2.基本使用
- <div id="box" style={{position: 'relative', width: '500px', height: '260px'}}>
- <Drag container="#box" size={[200, 200]}>
- <p>Mr xu</p>
- </Drag>
- </div>
我們只需要以上幾行代碼就能實現(xiàn)組件的自由拖拽. 效果如下:

解決可視化搭建平臺頁面層級的問題
目前在 h5-dooring 是通過橫向擴展來解決組件層級和嵌套的問題, 如果我們采用自由拖拽布局, 層級和嵌套的問題就很好解決了. 在 @alex_xu/rc-drag 這個庫中筆者實現(xiàn)設置層級的功能, 所以我們可以通過給拖拽組件設置不同的層級, 來實現(xiàn)頁面元素疊加和層的概念. 如下設置:
- <Drag container="#box" size={[10, 50]} zIndex={10}>
- <p>Mr xu</p>
- </Drag>
我們通過給組件設置更高的層級來實現(xiàn)組件堆疊的效果.
實現(xiàn)組件靜態(tài)化
我們往往會在編輯頁面時對組件進行拖拽等操作, 但是有些場景我們需要讓組件固定, 比如頭部或者頁腳, 或者鎖定某個元素, 類似于 PS 里圖層鎖定. 另一個場景是我們要實現(xiàn)公共的頁面渲染器, 在編輯狀態(tài)下可以自由拖動縮放, 但是在預覽狀態(tài)下需要讓元素固定, 不能出現(xiàn)自有拖拽等功能, 類似 h5-dooring 那種模式, 這個時候我們需要讓拖拽組件@alex_xu/rc-drag支持靜態(tài)化. 這個時候我們可以設置isStatic屬性為true, 如下圖:

代碼如下:
- <Drag container="#box" isStatic={true}><p>static item</p></Drag>
我們可以利用這個屬性, 寫個頁面渲染器, 用戶在預覽時將組件的isStatic設置為true即可, 源碼的底層實現(xiàn)其實也很簡單, 就是利用react-hoooks的組件編寫方式寫個判斷即可:
- {
- isStatic ?
- <div className="x-drag-item" style={style}>{ children }</div>
- :
- <div
- className="x-drag-item"
- style={style}
- onMouseDown={(e) => onMouseDown('move', e)}
- onMouseUp={onMouseUp} onMouseMove={onMouseMove}
- >
- </div>
- }
實現(xiàn)組件數(shù)據(jù)上報
我們都知道組件單純只有拖拽縮放能力遠遠不能滿足業(yè)務需求, 對于可視化拖拽組件, 更重要的是要能保留拖拽后的數(shù)據(jù), 比如寬高,位置,層級等數(shù)據(jù), 所以我們需要監(jiān)控幾個事件, 并將數(shù)據(jù)傳給對應的事件來讓外層能監(jiān)聽和獲取. 這里筆者提供了兩個拖拽回傳方法:
- onDrapStart
- onDrapStop
后面根據(jù)實際情況可以對應添加. 我們可以在父組件中綁定對應的方法, 如下:
- <Drag
- container="#box"
- size={[200, 200]}
- zIndex={2}
- onDragStart={(item) => console.log('start', item)}
- onDragStop={(item) => console.log('stop', item)}
- >
- <p>Mr xu</p>
- </Drag>
這樣我們就能在父層拿到對應的數(shù)據(jù)并保存下來了, 進而也就能實現(xiàn)我們的預覽頁面的功能了. 具體可以參考H5-Dooring 渲染器的部分.
支持移動端拖拽
目前筆者已經(jīng)支持移動端使用@alex_xu/rc-drag組件了,我們?nèi)绻鲆苿佣说腍5編輯器, 可以直接使用它來實現(xiàn)拖拽功能.

以上幾個技術(shù)點和技術(shù)實現(xiàn)是可視化拖拽組件必備的要素, 大家可以使用參考一下.
