在上篇文章,我们已经设计了一个简单的设计态的Canvas,能够显示经过BuildEngine生成的ReactNode进行渲染。本文,我们将继续上一篇文章的成果,设计并实现一个能够显示组件节点大纲树的组件。
什么是组件大纲树?
我们希望用户能通过一个地方比较明显的看到当前整个ComponentNode的树状结构;当用户点击某个ComponentNode的时候,既能够在DesignCanvas上高亮当前选中的UI元素,同时对于组件大纲树上也能高亮对应的树状节点。
PS:我们所设计的低开前端平台定位是轻量级。所以,我们在构建整个平台核心库的时候,并不会设计的非常复杂,本次我们将不会设计直接将元素进行拖拉拽到画布的内容,而是会围绕整个节点大纲树,来优化我们的低开体验。
如何设计实现大纲树与设计态UI界面的统一?
在本次设计与开发之前,我们需要回顾一下上篇文章中(低代码平台前端的设计与实现(三)设计态画布DesignCanvas的设计与实现 - 知乎 (zhihu.com))关于DesignCanvas的设计。DesignCanvas的过程设计如下:
正如上图所示,DesignCanvas的执行过程中,step4 -> data5 -> step6 -> data7
是在一个函数处理过程中的。
为了实现本次的需求,我们可能需要对上述的过程进行一定的优化,达到UI的渲染与元素节点大纲树组件在同一个DesignCanvas中的渲染的目的。在讨论如何修改前,我们先采用一个流程图来展示这个过程:
从上图,我们可以很容易的知道,为了让ComponentNode树到UI界面的生成与ComponentNode树到节点大纲树的生成是一致且同步的。我们需要将ComponentNode object和selectedNodePath再交给组件大纲树进行渲染。
在这样一套设计下,无论点击大纲树任意树节点,还是点击设计态UI界面的任意UI组件。我们都能够通过相关的事件(对于大纲树来说是树节点的点击事件;对于设计态UI界面上的UI组件来说是前面设计的wrapper的点击事件)拿到当前点击的元素的唯一path标识;然后,我们将拿到的path标识设置给selectedtNodePath这个state,最后再由该state来同时控制大纲树的节点高亮和设计态UI界面上的UI组件的边框高亮。这个过程由下面的流程图来简单描述:
大纲树组件实现
首先,我们选择了antd5的Tree树形组件。对于该组件我们会以受控的方式来使用,具体来讲,Tree树形组件的节点选中通过属性selectedKeys
控制;树形组件的节点展开通过属性expandedKeys
来控制。当然,一旦我们选择该组件以受控方式使用,那么不可避免的需要用对应的onSelect事件
和onExpand事件
来获取当前状态值,再交给上述的selectedKeys
和expandedKeys
。
Tree组件的基本用法
本节内容主要讲antd5的Tree树形组件的基本用法,目的是为了后面我们具体的大纲树组件做基础准备,可以完全当作独立的一节内容来看。
Tree的selectedKeys接收的是一个数组,用以表现被选中的节点。但需要特别注意:
Tree在默认的使用场景下是单个选中。也就是说,用户点击任意一个节点时,就选中该节点;点击其他节点,则选中其他节点。同一时间只会有一个被选中的节点。selectedKeys
尽管是一个数组,但在单选场景下,要不是一个空数组来表示没有节点选中,要不是一个只有一个元素的数组,表示某一个节点选中。下面用一个Demo来演示:
1 |
|
然后,编写一段代码,将selectedKeys设置为1-2-1
,也就是说,我们选中了上面的1-2-1
节点:
1 |
|
这个例子的效果如下:
从上面的gif可以看到界面渲染后,选中的节点就是1-2-1
。同时,其他的节点无论我们如何点击,都不会有任何的效果(受控)。为了能够点击后,让Tree组件选中对应的节点,我们需要将selectedKeys
至少作为一个state来存放,然后通过onSelect来设置该state:
1 |
|
上述的过程,可以用如下的数据流来描述:
上述过程中,currSelectedKeys表明当前选中的Keys(默认的单选模式下,是一个长度为1或0的数组),传给Tree的属性selectedKeys
,Tree组件的UI展示的过程中使用根据selectedKeys
来高亮对应节点;当然,我们点击任意节点的时候,会触发onSelect事件,该事件第一个参数就是点击选中的节点的Keys,我们可以直接将这个值再次设置给currSelectedKeys这个state。在上述的代码下,我们可以看到效果如下:
现在,我们分析了selectedKeys
后,再来分析一下Tree树形组件的expandedKeys
。这个属性是一个数组,控制整个Tree节点展开的Keys。我们首先将该值设置为:['1']
:
1 |
|
然后查看Demo效果:
可以看到,无论怎样点击节点左侧的三角,都无法展开或收起对应的子节点。类似的,我们使用一个state来存储展开的节点,然后使用onExpand事件来设置,即可达到效果:
组件大纲树面板
有了上面关于antd5的Tree树形组件的受控方式的使用基础,我们开始设计我们自己的组件大纲树组件,这里我们为它取名为:ComponentNodeTreeDesignPanel
。该组件的props如下:
1 |
|
我们再来讨论下这些属性如何关联内部的antd Tree树形组件的渲染与行为的。这里,我直接用一个流程图来描述:
上述过程具体为:
-
首先,为了呈现组件节点树状UI,很容易知道至少需要将ComponentNode对象传入,因为该对象本身就是树形的,只需要进行简单的数据转换即可完成Tree的树形数据格式,并渲染;
-
其次,为了达到高亮对应的节点效果,则需要传入当前选中的节点的唯一标识
path
,在内部转换为selectedKeys和expandedKeys; -
最后,当我们点击Tree的节点时候,需要把对应的节点信息传到上层,让外部再次控制传入当前选中的ComponentNode的path,形成一个闭环的数据流。
当然,这里面还涉及一些转换,还有path的构成规则。这里不再赘述,感兴趣的读者可以阅读有关ComponentNodeTreeDesignPanel
的组件代码。
最终效果:
附录
本次的内容已经提交至Github,并在打上了相应的Git tag标识:
https://github.com/w4ngzhen/lite-lc/tree/chapter_04
commit信息(倒序):
1 |
|