赞
踩
接上一篇《低代码数据可视化开源项目源码阅读总结》的博客,我们继续研究该项目中的重难点技术实现。
点击(双击或者单击)选中组件的规则,笔者研究过阿里云datav项目,发现datav-vue项目和阿里云的点击规则并不完全相同。
但是两个项目的点击规则都遵循下图中文字总结的规则。通过满足这两个规则:双击选中向内一层的组件,单击选中同级组件,就可以实现选中画布中所有层级的组件了。
datav-vue点击选中的实现逻辑比较复杂,笔者阅读了很久方才理解。
通过给画布的组件绑定onDown事件,实现单击选中的逻辑,onDown事件阻止冒泡,所以onDown事件只有最内层的组件能触发onDown事件,但是至于我们决定选中哪个组件,是根据以下逻辑来实现的:
(1) onDown事件的事件对象组件,如果满足以下两个条件中的一个,那么选中事件对象组件:
条件一:无父组件,那么选中事件对象组件自己;
条件二:有父组件并且自己的同级或者父组件的更内层的组件被选中了,但是自己没有被选中,那么选中自己。
(2)onDown事件的事件对象组件有父组件,并且父组件内部没有一个组件是被选中的,那么找到事件对象组件最远的一个内部没有选中任何组件的祖先组件,选中该祖先组件。
通过给画布的组件绑定onDoubleClick事件,实现双击选中的逻辑,
阻止了冒泡,所以只有最内层的组件能触发onDoubleClick事件,但是至于我们决定选中哪个组件,是根据以下逻辑来实现的:
我们找到onDoubleClick事件对象的所有祖先组件,找到被选中的祖先组件,对该祖先组件向内一层的组件(要么是事件对象组件的祖先组件,要么是事件对象组件本身)进行选中。
我们需要给每个图层项目绑定上dragEnter,dragEnd事件,在dragEnter事件中记录要移动去的位置信息,在dragEnd事件中进行移动操作。
移动组件的函数的核心思路是:
(1)如果toCom和被选中拖拽的组件的父级图层相同,根据toIndex在图层树结构整体数据中找到对应的图层a,将共同父级下的选中的图层清除,那么父级下只剩下未选中的图层了,我们在这里找到图层a的索引位置,将选中的图层插入其后。
(2)如果toCom和被选中拖拽的组件的父级不同,从选中组件的父组件中清除掉选中的组件,如果导致父组件无子组件了,那么清除父组件(父组件以上的祖先组件也一样), 如果父组件还有子组件,那么调整父组件等祖先组件的位置尺寸等数据。最后将选中的组件添加到toCom的父组件下,并且调整toCom的所有祖先组件的位置大小信息
为了方便各个组件数据源数据的统一管理,我们专门创建dataSource的全局数据store中心,存储dataMap对象,dataMap的key是各个组件的id,value值是各个组件的数据源数据,画布中组件初次加载的时候,将组件的数据挂载到dataMap上,组件展示的数据便是根据组件id,去dataMap中获取进行展示;当组件的数据源配置变化的时候,我们将新的数据源数据更新到dataMap对象上即可。
在阅读开源代码的画布代码和组内配置代码时,发现一个问题,当配置成组组件的透明度的时候,组内组件的操作框也变得透明,这里的实现是有问题的。笔者阅读其画布中的组件代码,发现因为组内组件(包含其操作框)因为嵌套在成组组件内部,所以设置成组组件透明度的时候,组内组件的操作框必然会受到影响。
我们理想的情况是操作框不受任何组件,组内配置的透明度的影响。这样,即便成组组件组内配置为完全透明的时候,我们仍可看到成组组件内部的组件的操作框,并且进行组件操作。
如下两图便是我们理想的实现的展示:
那为了实现以上理想的效果,我们实现画布中组件的展示的思路应当是:
将操作框从画布中的组件库组件中抽离出来,
画布中某个组件的展示的实现由两层组件来完成:第一层是组件的纯ui的展示(包括透明度),只负责展示组件内容,第二层是组件的操作框的展示,在操作框这层去设置监听器,以便进行拖拽、拉伸等操作。这样一来,因为操作框从组件中剥离开,当我们设置成组组件的透明度的时候,操作框便不受影响。
<div className="canvas-main"> <div id="canvas-wp" className="canvas-panel-wrap" onClick={cancelSelected}> <div id="screen-wp" className="screen-shot" style={screenShotStyle} onMouseDown={handleMouseDown} > // 第一层:画布中组件的ui展示层 <div id="canvas-coms" className="canvas-panel" style={canvasPanelStyle}> <div className="ui-layer"> {rootWidget.children.map(com => ( // 在DatavTransformUI组件中配置透明度 <DatavTransformUI key={com.key} com={com} /> ))} </div> </div> // 第二层:画布中组件的操作框展示层 <div id="action-canvas-coms" className="canvas-panel" style={actionCanvasPanelStyle} onDragOver={dragOver} onDrop={dropToAddCom} > // 在DatavTransform组件中实现操作框的展示,实现组件拖拽,拉伸等操作 <div className="action-layer"> {rootWidget.children.map(com => ( <DatavTransform key={com.key} com={com} /> ))} </div> </div> <Ruler /> </div> </div> </div>
实现的核心思路:复用1.4中的ui展示层代码
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。