布局语言
在Nop平台中,我们通过NopLayout这一专用于表单布局的领域特定语言来实现表单布局信息和(字段级)内容信息之间的分离。例如对于如下表单布局
|
对应显示
一. 布局语法
NopLayout规定了如下规则:
指定每行显示的字段,例如
a b
表示本行显示a
和b
字段通过
fieldName[displayName]
指定字段名以及对应的显示名通过
===分组名[分组Label]===
标记分组如果为分组指定Label,则使用
FieldSet
控件来显示分组,并通过符号^
表示分组收缩,符号>
表示分组展开在字段名前标记符号
@
, 表示该字段是只读字段,前台使用view模式的控件去显示在字段名前标记符号
!
,表示不显示Label。
例如在用户列表的左侧增加按照部门进行过滤,本质上是在左侧引入一个过滤表单
|
deptId
字段前标记符号!
,表示不显示Label,最后得到
二. 字段控件推定
字段级别的显示控件一般情况下可以根据数据模型中定义的字段类型和数据域来推定。
例如对于字段gender
,我们指定了它使用auth/gender
这个字典,取值范围只能是字典范围内的值。对于字段email
,它的数据域(domain)设置为email
,要求录入格式必须是满足email格式规范。
具体推导需要使用的控件时,首先会确定字段的编辑模式(一般与表单的editMode
设置相同,但可以单个字段指定),然后在control.xlib
控件标签库中按照如下顺序依次查找,以第一个匹配的控件为准:
查找名称为
{editMode}-{control}
的控件,control
为在cell
配置中明确指定的control
属性。查找名称为
{editMode}-{domain}
的控件,例如<edit-email/>
如果配置了字典项,则查找名称为
{editMode}-enum
的控件查找名称为
{editMode}-{stdDomain}
的控件,stdDomain
是系统全局注册的标准数据域,相当于是对普通数据类型的一种细化,例如stdDomain=xml
表示文本字段,但存储的内容是xml格式等。如果是外键关联,则查找名称为
{editMode}-to-one
的控件,尝试使用关联对象选择控件。查找名称为
{editMode}-{dataType}
的控件,例如<edit-string/>
和<edit-double/>
如果
editMode
不是edit
,也不是view
, 则按照edit
模式,从第一步开始重新查找一遍如果是
view
模式,则使用<view-any/>
控件,否则使用<edit-any/>
控件。
editMode
分为add/view/update/edit/query
等多种模式,主要用于区分字段的不同使用场景。在不同的使用场景下我们可能会使用不同的控件。例如在编辑模式下我们可以会使用单选控件,但是在查询模式下我们可能会选择使用多选查询控件,但是在表单布局中我们可以使用同样的字段名来表示该字段。
字段控件推定是一个可扩展的机制。当我们在业务上不断发现字段级别的重复语义时,我们可以在数据模型中为它们单独指定一个独特的domain,这样在前端我们就会自动对所有标记为这一domain的所有字段使用统一的控件来展示。我们所需要做的工作为两步:
在数据模型中定义
domain
, 并为字段指定domain
在
control.xlib
中增加不同编辑模式下的控件实现(例如对于domain=roleId
,可以增加<edit-roleId/>
、<view-roleId/>
、<query-roleId/>
)。或者不直接修改control.xlib
,利用Delta差量定制机制,对系统内置的control.xlib
进行扩展即可。
用户自定义domain
的处理过程与系统内置的domain
的处理过程是完全一致的。
如果控件比较特殊,而且没有抽象为统一domain
的价值,则我们也可以选择直接指定表单中使用的显示控件,例如
|
gen-control
是执行XPL模板语言来生成json控件描述。
三. 字段联动
在布局信息之外,我们可以通过补充的cell
配置来指定字段间的联动信息。例如
|
cell
不仅仅可以用于指定单个字段,它还可以对应于字段分组,从而为一组字段指定显示/隐藏条件。例如上例中menuProps
对应于一组字段,仅当resourceType != 'FNPT'
时才会显示。
四. 原型继承
信息化系统中,一个经常出现的情况是新增、修改、查看表单的布局基本一致、甚至完全相同,但是修改和查看的时候使用的控件不同。对于这种部分层面相似或者相同的场景,一般的技术很难实现复用,而在Nop平台中借助于可逆计算原理,我们提供了一个标准化的解决方案:
将公共的、可能得到复用的信息抽象为某个DSL语法节点
利用X语言中内置的
x:prototype
机制,可以将某个兄弟节点作为模板来构造自身通过
x:prototype-override
来对模板进行差量定制
具体到前台表单方面的应用,具体做法为:
将表单布局抽象为
<form/>
节点定义
<form id="default" x:abstract="true"/>
作为模板,view/edit表单的x:prototype
设置为default
可以通过
<cell/>
节点调整具体字段的显示
|
x:abstract
是XLang语法中规定的一个特殊属性,如果它设置为true
,则表示本节点仅作为模板来使用,在最终合并生成的结果中会被自动删除,类似于Spring的XML配置中的abstract
属性的作用。
五. 扩展布局
NopLayout布局语言还可以支持更复杂一些的布局结构。比如说它支持多级嵌套布局
|
在分组标记中,可以通过符号#
来表示嵌套层级,类似于Markdown语法,可以通过多个#
来表示层级数。##
表示是#
的子节点。