LowCode 是高效、高性能的拖拽式低代码开发平台. 也是笔者最近一直在研究的方向, 对于可视化搭建平台的实现方案笔者之前写过很多文章, 这里带大家探索一个新方向——基于自然流布局的可视化搭建平台.
在我们之前实现的 h5-dooring 搭建平台中, 我们采用了网格布局的方式来实现拖拽生成H5页面或者Web app, 其好处就是灵活简单, 用户基本没有任何使用成本, 在前端层也能做一定的横向扩展, 但是存在几个缺陷:
实现嵌套组件比较复杂
没有层的概念
虽然通过改造可以实现层和嵌套的问题, 最近也在努力往这个方向实现(虽然和设计初衷相驳, dooring的初衷是抹去层和嵌套的概念, 让搭建扁平化和智能化, 所以没有采用自由布局的方案)
但是如果一定要实现嵌套和层的功能, 有没有另一种更简单的方案呢? 笔者目前想到了两种解决方案:
- 将智能布局改为自由布局, 即可以采用类似 react-resizable 的这种方案
- 基于自然流来实现, 也就是抹去定位的概念, 完全基于元素在文档的顺序, 层级和定位的选择权交给用户
因为第一种方案笔者在dooring的早期已经实现过一版, 最后弃用采用了网格布局, 所以说我们来探讨一下第二种方案的实现.
基于自然流布局实现拖拽生成页面
自然流布局的好处就是我们不用通过定位的方式来限定元素的位置等信息, 而是以html文档流的方式来布局元素, 并且用户可以灵活的设置元素的层级(layer)和偏移(transform), 接下来我们来看看简单的实现效果.
1. demo效果
由上图的demo我们可以发现组件在画布中的布局完全是默认的文档流的方式, 所以我们有更灵活的布局实现.
2. 实现思路
具体实现思路主要分以下几个部分:
- 组件区拖拽至画布
- 画布区拖拽
- 组件编辑器和更新机制
第一点和第三点我们在 H5-dooring中已经实现了, 感兴趣的可以看我之前的文章, 我们这里重点来实现画布区拖拽, 也是比较核心的环节.
2.1 H5拖放api基本介绍
拖放(Drag 和 drop)是 HTML5 标准的组成部分, 早已被大多数浏览器支持. 我们目前使用的拖放插件基本上基于 H5 拖放 API 来实现的, 其实实现第一点组件区拖拽至画布我们完全可以用原生来实现, 这里笔者简单来介绍以下.
首先我们来看看一个完整的拖放过程:
- 首先要设置一个元素可拖放(比如)
- 设计拖动的时候会发生什么(需要用到ondragstart事件 和 setData(你要传递的数据))
- 放到何处,也就是目标容器(通常在目标容器上绑定ondragover和ondrop事件)
有了以上3个步骤, 我们就能实现第一点的需求, 笔者写个简单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" />
也就是对应的我们的组件拖放区域, 如下图所示:
2.2 画布区拖拽布局实现
因为之前的版本我们采用了网格布局来实现智能拖拽, 由于内部定位机制采用的是绝对定位(absolute), 所以是实现层级和固定组件比较困难, 如果组件的呈现完全脱离了定位的束缚, 我们就可以实现以上的困境了. 所以这里我们调研了一种方案——拖拽排序机制.
自然流布局的规律就是默认情况下html页面是基于dom出现的顺序来排列的, 也就是我们说的堆叠.
我们可以遵循这样的设计, 通过排序的方式改变组件的位置从而实现自然流布局的页面搭建.
那么我们再回到上面说的布局问题, 比如说要想实现栅格化布局, 我们只需要定义一个flex容器, 将组件拖拽到容器里就好了, 这样也就解决了嵌套的问题. 同时我们还可以设计嵌套容器的栅格数, 这样就可以实现类似如下的效果:
拖拽排序的库我们可以使用:
- sortable
- Vue.Draggable
- react-dnd
还有很多优秀的库, 这里就不一一举例了.
3. 如何实现层级和嵌套
其实在上面的实现思路中我们已经解决了嵌套的问题了, 即提供拖放的容器组件, 利用笔者在上文中介绍的拖放api即可实现. 对于组件层级来说, 因为我们采用的是自然流布局, 所以我们可以轻松的设置元素的定位属性, 比如我们提供一个定位的设置:
关于如何设计一个动态的属性编辑器, 笔者之前文章中也就详细的介绍, 大家可以参考:
表单编辑器实现(FormEditor)
以上就是自然流布局的基本实现方式, 后续笔者也会在github上同步我们最新的成果.H5-Dooring编辑器wiki: https://github.com/MrXujiang/h5-Dooring/wiki