基于自然流布局的可視化拖拽搭建平臺設(shè)計方案
LowCode 是高效、高性能的拖拽式低代碼開發(fā)平臺. 也是筆者最近一直在研究的方向, 對于可視化搭建平臺的實現(xiàn)方案筆者之前寫過很多文章, 這里帶大家探索一個新方向——基于自然流布局的可視化搭建平臺.
在我們之前實現(xiàn)的 h5-dooring 搭建平臺中, 我們采用了網(wǎng)格布局的方式來實現(xiàn)拖拽生成H5頁面或者Web app, 其好處就是靈活簡單, 用戶基本沒有任何使用成本, 在前端層也能做一定的橫向擴展, 但是存在幾個缺陷:
實現(xiàn)嵌套組件比較復(fù)雜
沒有層的概念
雖然通過改造可以實現(xiàn)層和嵌套的問題, 最近也在努力往這個方向?qū)崿F(xiàn)(雖然和設(shè)計初衷相駁, dooring的初衷是抹去層和嵌套的概念, 讓搭建扁平化和智能化, 所以沒有采用自由布局的方案)

但是如果一定要實現(xiàn)嵌套和層的功能, 有沒有另一種更簡單的方案呢? 筆者目前想到了兩種解決方案:
- 將智能布局改為自由布局, 即可以采用類似 react-resizable 的這種方案
- 基于自然流來實現(xiàn), 也就是抹去定位的概念, 完全基于元素在文檔的順序, 層級和定位的選擇權(quán)交給用戶
因為第一種方案筆者在dooring的早期已經(jīng)實現(xiàn)過一版, 最后棄用采用了網(wǎng)格布局, 所以說我們來探討一下第二種方案的實現(xiàn).
基于自然流布局實現(xiàn)拖拽生成頁面
自然流布局的好處就是我們不用通過定位的方式來限定元素的位置等信息, 而是以html文檔流的方式來布局元素, 并且用戶可以靈活的設(shè)置元素的層級(layer)和偏移(transform), 接下來我們來看看簡單的實現(xiàn)效果.
1. demo效果

由上圖的demo我們可以發(fā)現(xiàn)組件在畫布中的布局完全是默認(rèn)的文檔流的方式, 所以我們有更靈活的布局實現(xiàn).
2. 實現(xiàn)思路
具體實現(xiàn)思路主要分以下幾個部分:
- 組件區(qū)拖拽至畫布
- 畫布區(qū)拖拽
- 組件編輯器和更新機制
第一點和第三點我們在 H5-dooring中已經(jīng)實現(xiàn)了, 感興趣的可以看我之前的文章, 我們這里重點來實現(xiàn)畫布區(qū)拖拽, 也是比較核心的環(huán)節(jié).
2.1 H5拖放api基本介紹
拖放(Drag 和 drop)是 HTML5 標(biāo)準(zhǔn)的組成部分, 早已被大多數(shù)瀏覽器支持. 我們目前使用的拖放插件基本上基于 H5 拖放 API 來實現(xiàn)的, 其實實現(xiàn)第一點組件區(qū)拖拽至畫布我們完全可以用原生來實現(xiàn), 這里筆者簡單來介紹以下.
首先我們來看看一個完整的拖放過程:
- 首先要設(shè)置一個元素可拖放(比如
)
- 設(shè)計拖動的時候會發(fā)生什么(需要用到ondragstart事件 和 setData(你要傳遞的數(shù)據(jù)))
- 放到何處,也就是目標(biāo)容器(通常在目標(biāo)容器上綁定ondragover和ondrop事件)
有了以上3個步驟, 我們就能實現(xiàn)第一點的需求, 筆者寫個簡單demo來給大家參考一下:
- <script type="text/javascript">
- function allowDrop(ev) {
- ev.preventDefault();
- }
- function drag(ev){
- ev.dataTransfer.setData("Text",ev.target.id);
- }
- function drop(ev){
- ev.preventDefault();
- let data=ev.dataTransfer.getData("Text");
- ev.target.appendChild(document.getElementById(data));
- }
- </script>
- <div id="box" ondrop="drop(event)" ondragover="allowDrop(event)"></div>
- <img id="drag" src="dooring.png" draggable="true" ondragstart="drag(event)" width="336" height="69" />
也就是對應(yīng)的我們的組件拖放區(qū)域, 如下圖所示:
2.2 畫布區(qū)拖拽布局實現(xiàn)
因為之前的版本我們采用了網(wǎng)格布局來實現(xiàn)智能拖拽, 由于內(nèi)部定位機制采用的是絕對定位(absolute), 所以是實現(xiàn)層級和固定組件比較困難, 如果組件的呈現(xiàn)完全脫離了定位的束縛, 我們就可以實現(xiàn)以上的困境了. 所以這里我們調(diào)研了一種方案——拖拽排序機制.
自然流布局的規(guī)律就是默認(rèn)情況下html頁面是基于dom出現(xiàn)的順序來排列的, 也就是我們說的堆疊.

我們可以遵循這樣的設(shè)計, 通過排序的方式改變組件的位置從而實現(xiàn)自然流布局的頁面搭建.
那么我們再回到上面說的布局問題, 比如說要想實現(xiàn)柵格化布局, 我們只需要定義一個flex容器, 將組件拖拽到容器里就好了, 這樣也就解決了嵌套的問題. 同時我們還可以設(shè)計嵌套容器的柵格數(shù), 這樣就可以實現(xiàn)類似如下的效果:
拖拽排序的庫我們可以使用:
- sortable
- Vue.Draggable
- react-dnd
還有很多優(yōu)秀的庫, 這里就不一一舉例了.
3. 如何實現(xiàn)層級和嵌套
其實在上面的實現(xiàn)思路中我們已經(jīng)解決了嵌套的問題了, 即提供拖放的容器組件, 利用筆者在上文中介紹的拖放api即可實現(xiàn). 對于組件層級來說, 因為我們采用的是自然流布局, 所以我們可以輕松的設(shè)置元素的定位屬性, 比如我們提供一個定位的設(shè)置:

關(guān)于如何設(shè)計一個動態(tài)的屬性編輯器, 筆者之前文章中也就詳細的介紹, 大家可以參考:
表單編輯器實現(xiàn)(FormEditor)
以上就是自然流布局的基本實現(xiàn)方式, 后續(xù)筆者也會在github上同步我們最新的成果.H5-Dooring編輯器wiki: https://github.com/MrXujiang/h5-Dooring/wiki