[TOC]
MetaX-UI Framework 元视图开发框架(简称 MetaX-UI)是一个基于元数据的Web和移动端界面开发框架,提供了一种全面元数据化的声明式、模式化的UI开发模式,帮助开发者区分界面开发中的“交互”和“样式呈现”这两类主要的任务。
MetaX-UI 框架基于高维抽象提供了标准化、模式化的“交互”实现来处理“少变”的部分任务,使开发者可以重点关注在“样式呈现”这部分“多变”的任务。特别是在复杂业务的情况下, 可显著地提升的 UI 界面的开发效率,提升对业务需求的响应速度。
MetaX-UI 框架不绑架开发者的技术选择,MetaX-UI 架构在当前主流的 Web 前端技术如 HTM5 、NodeJS、 Vue 等技术之上,有良好的架构开放性。
在 MetaX-UI 中,“元数据(Metadata)”是用户界面(UI)的逻辑定义数据,它描述了“样式无关的 UI 交互的核心逻辑”,它的本质是用户界面中不会跟随样式变化的基本逻辑。MetaX-UI 的核心设计思想是区分用户界面中的“不变”与“变化”,把用户界面设计中的“交互逻辑”和“呈现样式”进行分离,独立地进行定义和管理,以实现跨越前端与后台的深度的组件化复用和扩展。
以下面的两个登录组件为例,解释一下什么是“样式无关的 UI 交互核心逻辑”:
<...未完成...>
“交互逻辑”和“呈现样式”的分离,一方面是通过抽象出一组通用的“交互逻辑”的形式化定义,并以结构化的“元数据”对“交互逻辑”进行描述,另一方面是基于现代 Web 前端技术对“呈现样式”进行设计实现,利用Web模板、层叠样式表等技术,实现用户界面设计实现的层次化 —— 具有默认的约定俗成的模式化呈现,同时可以局部调整具体样式,也可以深度地实现新的呈现样式。通过这样的分离,开发者基于 MetaX-UI 默认的组件模板下只需要定义好“元数据”——UI交互逻辑,便可以快速灵活地完成UI的开发;同时,这种分离也有利于前端界面开发与后端系统开发的衔接和集成,实现全栈的深度工程化和组件化。
安装 MetaX-UI 之前需要先安装 Vue3.0 。建议先安装 Vue Cli ,通过 Vue Cli 创建项目会更加方便。
# Vue Cli 采用全局安装;
npm install -g @vue/cli
安装 Vue Cli 的官方教程:https://cli.vuejs.org/zh/guide/installation.html
安装成功 Vue Cli 之后,可以使用 vue 命令来创建 Vue 项目。
新创建的项目具有完整的结构和示例的组件,可直接编译运行起来。
# 创建项目:my-app ;
# 执行 vue create 命令时首先会提示选择 vue 的版本,请选择 vue3.0 ;
# vue create 命令会在当前目录创建子目录 my-app 作为项目的根目录;
# 如果项目目录已存在,则会提供操作选项,可选值覆盖、合并等操作。
vue create my-app
# 进入项目目录,编译项目;
cd my-app
npm run build
# 运行项目可以看到项目的示例组件的界面;
npm run serve
# 在项目根目录 my-app 下执行命令;
npm install --save metax-ui
修改项目的入口文件 main.js ,增加以下内容:
+ import MetaXComponents from "metax-ui";
+ app.use(MetaXComponents);
完整的 main.js 如下:
import { createApp } from "vue";
import App from "./App.vue";
+ import MetaXComponents from "metax-ui";
const app = createApp(App);
+ app.use(MetaXComponents);
app.mount("#app");
至此,已经完整地创建了一个 MetaX-UI Framework 的项目,可以开始在组件中运用元数据驱动的 MetaX-UI 组件来快速创建企业级的前端应用。
进一步的内容请继续浏览下一章节:3. 快速开始
至此,已经建立起了一个最基础的 MetaX 前端应用。
MetaX-UI 将 Element Plus 的SVG图标库 @element-plus/icons 进行了全局注册,全部重新以 "el-svg-" 前缀,以避免与标准 HTML 标签的命名冲突。
使用方式有两种:
-
直接使用 Element Plus 的 SVG 图标: 直接采用前缀 'el-svg-' 加图标名称作为完整的标签名,例如:图标'MessageBox'的 svg 标签为 'el-svg-message-box'
<template> <div> <!-- 由于 svg 图标默认不包含任何属性,所以需要自行定义 --> <el-svg-edit style="width: 1em; height: 1em; margin-right: 8px;" /> <el-svg-share style="width: 1em; height: 1em; margin-right: 8px;" /> <el-svg-delete style="width: 1em; height: 1em; margin-right: 8px;" /> <el-svg-search style="width: 1em; height: 1em; margin-right: 8px;" /> <el-svg-message-box style="width: 1em; height: 1em; margin-right: 8px;" /> </div> </template>
-
通过 x-icon 组件使用 x-icon 组件对原始的图标进行了包装,可以通过属性指定具体的图标类型,以及长宽等其它一些属性。这种包装是基于 VUE 的动态组件机制实现的,因此可用的图标并不限于默认注册的 el-svg 图标,也可以是应用中注册的任何图标组件。
<template> <div> <x-icon icon="el-svg-share" width="10px" height="10px;" /> <x-icon icon="el-svg-delete" width="10px" height="10px;" /> <x-icon icon="el-svg-search" width="10px" height="10px;" /> <x-icon icon="el-svg-message-box" width="10px" height="10px;" /> <x-icon icon="your-icon" width="10px" height="10px;" /> </div> </template>
详细图标请参考 Element-plus/icons 完整图标库,以及Element+ Icon图标教程
框架组件:定义了一个应用的标准的上下文,包括元数据、状态管理和数据源,并基于布局组件之上定义了功能区的装配、布局和交互管理。
-
属性 描述 类型 值范围 默认值 metadata 框架元数据 FrameworkMetadata — — layout-mode 布局模式。 可选值: h / v 。h 表示水平布局; v 表示垂直布局;如果不设置,则采用水平布局; String h / v h aside-width 边栏宽度 String — 200px
-
事件 描述 参数列表 返回值 异常 menu-select 菜单选择事件;当菜单项被选择时触发。 — — — toolbar-button-click 工具按钮点击事件;当工具栏的按钮被点击时触发。 — — — -
| 插槽 | 描述 | |:----|:---- |:---- | |view|视图区,页面的主体区域,用于显示与导航菜单项关联路由的组件。|
-
-
插槽:view
属性 类型 描述 frameworkMetadata FrameworkMetadata 框架元数据;
-
插槽:view
-
布局组件定义了一组标准的功能区以及相应的布局。
水平布局组件的总体布局划分分为4个栏位:边栏、页头、视图、页脚; 通过这 4 个栏位进行局部尺寸控制;
水平布局组件的栏位分布:
|----------------------------------------------------------|
| | 页头 |
| |------------------------------------------------|
| | |
| | |
| 边栏 | 视图 |
| | |
| | |
| |------------------------------------------------|
| | 页脚 |
|----------------------------------------------------------|
水平布局组件在栏位的基础上进一步划分功能区,具体如下:
- “边栏”栏位垂直划分为上下两个功能区:图标、导航;
- “页头”栏位水平划分为左右两个功能区:标题、工具;
- “视图”栏位整体作为一个功能区:视图;
- “页脚”栏位整体作为一个功能区:页脚;
水平布局组件的功能区分布:
|----------------------------------------------------------|
| 图标 | 标题 | 工具 |
| |------------------------------------------------|
|---------| |
| | |
| | |
| | 视图 |
| 导航 | |
| | |
| |------------------------------------------------|
| | 页脚 |
|----------------------------------------------------------|
-
水平布局组件的功能区扩展插槽列表:
- 图标区: logo ;
- 导航区: nav ;
- 标题区: headline ;
- 工具区: tools ;
- 视图区: view ;
- 页脚区: footer ;
-
属性 描述 类型 值范围 默认值 aside-width 边栏宽度 String — 200px header-height 页头高度 String — 80px footer-height 页脚高度 String — 60px aside-divider 是否在边栏的“图标区”和“导航区”之间显示分隔线 Boolean — false -
事件 描述 参数列表 返回值 异常 — — — — — -
插槽 描述 logo 图标区 nav 导航区 headline 标题区 tools 工具区 view 视图区 footer 页脚区
-
属性 描述 类型 值范围 默认值 metadata 菜单元数据 MenuMetadata — — vertical 是否垂直布局;如果不设置,或者为 false,则采用水平布局; Boolean — false -
事件 描述 参数列表 返回值 异常 — — — — — -
插槽 描述 默认值 — — —
-
属性 描述 类型 值范围 默认值 metadata 工具栏元数据 ToolbarMetadata — — vertical 是否垂直布局;如果不设置,或者为 false,则采用水平布局; Boolean — false -
事件 描述 参数列表 返回值 异常 button-click:[buttonKey] 带修饰符的工具按钮点击事件。
当修饰符[buttonKey]对应的按钮被点击时触发此事件。ButtonClickEvent — — button-click 工具按钮点击事件。
当任何一个按钮被点击时触发此事件。
此事件发生在“带修饰符的工具按钮点击事件”之后。ButtonClickEvent — — -
插槽 描述 默认值 — — — -
-
{ buttons:[], // 类型: ToolButtonMetadata 数组; }
-
{ /** * 按钮显示的文本名称; */ name; /** * 按钮的唯一 key ; * * 当点击按钮触发事件时, key 会传递给事件相应函数; */ key; /** * 是否禁用按钮; */ disabled; /** * 图标类; */ icon; /** * 类型; * * 接受的值:primary / success / warning / danger / info / text ; * * 默认为 text; */ type = "text"; /** * 路由的目标视图的名称; * * 如果定义了,则当菜单项被选择时,触发到指定视图的路由跳转; */ routeView; /** * 路由的目标路径; * * 如果定义了,则当菜单项被选择时,触发到指定路径的路由跳转; * * 当同时定义了 routeView 和 routePath 属性时,以 routePath 为高优先级而忽略 routeView ; */ routePath; }
-
-
属性 描述 类型 值范围 默认值 metadata 工具栏元数据 DataViewMetadata — — dataset 数据集;表格组件根据数据集维护的状态和数据进行呈现 Dataset — — selection-column 是否显示选择列; Boolean — false index-column 是否显示索引列; Boolean — false index-column-label 索引列的标题; String — "#" operation-column-label 操作列的标题; String — "操作" page-size-options 分页大小的选项列表; int[] — [5, 10, 15, 20, 30, 50, 100] -
事件 描述 参数列表 返回值 异常 all-selection-change 选择列的列头“全选”选项变更时触发此事件。 allSelected :全选状态; true 表示全选,false 表示取消全选; — — -
插槽 描述 默认值 — — —
-
属性 描述 类型 值范围 默认值 metadata 工具栏元数据 DataViewMetadata — — dataset 数据集;表格组件根据数据集维护的状态和数据进行呈现 Dataset — — selection-column 是否显示选择列; Boolean — false index-column 是否显示索引列; Boolean — false index-column-label 索引列的标题; String — "#" operation-column-label 操作列的标题; String — "操作" page-size-options 分页大小的选项列表; int[] — [5, 10, 15, 20, 30, 50, 100] -
事件 描述 参数列表 返回值 异常 all-selection-change 选择列的列头“全选”选项变更时触发此事件。 allSelected :全选状态; true 表示全选,false 表示取消全选; — — -
插槽 描述 默认值 — — —
-
属性 描述 类型 值范围 默认值 metadata 表单元数据 DataViewMetadata — — data-model 数据模型;表单组件根据数据模型的定义建立交互呈现以及数据验证; DataModel — — data-binding 数据项;;表单组件显示的数据记录; Object — — label-width 字段标签的宽度; String — — label-align 字段标签的对齐方式;有 3 个可选值: left, right, top; String "left", "right", "top" "right" layout-columns 字段的布局的列数;
类型为整数,有效范围 [1 - 10],默认值为 1 ;
表单组件采用 Grid 布局,此字段定义了 Grid 布局的列数;
举例:
列数为 2 ,则把空间平均分割为 2 列,所有的字段按行从左边第 1 列依次分布;
当占据满 1 行以后从下一行从左边第 1 列再依次分布,直到布满所有的字段控件为止;int [1 - 10] 1 field-span 默认的字段布局跨度 int [1 - 10] — field-span:<fieldKey> 针对特定字段的布局跨度; <fieldKey> 为 metadata 中的字段的 key 属性;参见FieldMetadata 的 key 属性; int [1 - 10] — readonly 是否只读 boolean true / false false -
方法 描述 参数列表 返回值 异常 edit 编辑表单数据。
调用方法后,表单进入编辑状态;如果调用前已处于编辑状态,则调用方法立即退出。— true :表示已经处于编辑状态。 如果表单是只读的(readonly 属性为 true),则引发异常。 isEditing 是否处于编辑状态。 — data-binding 属性绑定的数据对象 — flush 将当表单控件上的输入刷新写入到 data-binding 属性绑定的数据对象。 — data-binding 属性绑定的数据对象 — submit 当表单控件上的输入被刷新写入绑定的数据对象时触发此事件。 handler : 处理函数;参数类型:{Function(newData, origData)}; 可选参数;
(1)如果没有设置处理函数,则在提交触发后直接将编辑产生的新的数据对象合并更新到表单绑定的数据对象(dataBinding);
(2)如果设置了处理函数,则在提交触发后先调用处理函数,传递2个参数——newData 编辑产生的新数据、 origData 编辑前的原始数据;
(3)处理函数在执行完成后:
(3.1)如果返回一个数据对象,则将该对象合并更新到表单绑定的数据对象(dataBinding);
(3.2)如果返回 undefined,则认为处理函数已经自行处理了新数据与原数据对象的更新合并,而不会再做额外的合并操作。data-binding 属性绑定的数据对象 — cancel 取消编辑。调用方法后清除表单控件至上一次 flush 操作依赖所有未提交的输入,取消后表单进入非编辑状态。 — — -
事件 描述 参数列表 返回值 异常 flush 当表单控件上的输入被刷新写入到 data-binding 属性绑定的数据对象后触发此事件。 — — — submit 当表单控件上的输入被刷新写入绑定的数据对象时触发此事件。 — — — -
插槽 描述 默认值 — — —
MetaX-UI 定义了以下几种基本数据类型:
类型 | 描述 | 默认值 |
---|---|---|
Bool | 布尔值 | false |
Int | 整数 | false |
Text | 文本 | "" |
Decimal | 小数 | 0.00 |
Timestamp | 时间戳 | 0 |
Bytes | 字节数据 | null |
Reference | 引用类型;指向一个特定的类的数据模型; | null |
注:对于 Decimal 类型,框架采用了精确小数计算的实现,能够避免原生的 Number 类型对于小数计算的不确定性。
数据模型由“类名称”属性值作为唯一标识,由一组字段组成;
class DataModel{
/**
* 类名称;
*
* 类名称是数据模型的唯一标识;
*/
className;
/**
* 字段列表;
*/
fields;
/**
* 创建表单数据;
*/
createFormData(data);
}
class Field{
/**
* 字段的键;通过 key 可以访问对象实例上的对应属性;
*/
key;
/**
* 字段的名称;
*/
name;
/**
* 字段的类型;值为 DataType 类型;共有 Bool、Int、Decimal、Text、Bytes、Timestamp、Reference 七种类型;
*/
type;
/**
* 字段值的内容类型;
*
* 用于指定字段内容为某一特定类型的数据的格式,例如 Text 类型下,可以有 JSON、XML 等格式;
*
* contentType 的格式参照了 HTTP 协议的 content-type header 的 MIME Type 格式:类型名/子类型名[ ; 可选参数 ] ,不区分大小写,不允许空格出现;
* 其中,参数的格式:参数名=参数值;参数名不区分大小写,中间不允许出现空格;
*
* 例如,对于 text 类型的字段,如果内容为 JSON 则表示为 text/json(或 application/json);如果内容为 XML 则表示为 text/xml (或 application/xml);
*
* 框架通过对参数列表进行扩展,以便对界面呈现提供更多的选项,例如 text/plain;charset=utf-8
*
* (MIME Type 详情参考 IETF 规范 RFC 7231:https://datatracker.ietf.org/doc/html/rfc7231#section-3.1.1.1)
*
* @returns ContentType 字段值的内容类型;
*/
contentType;
/**
* 字段值的规则;
*
* 表示字段值的合法范围的规则,通过校验函数能够检查值是否符合规则要求;类型为 DataRule[] 数组;
*/
rules;
/**
* 创建字段默认值的函数;
*
* 如果未定义,则采用类型的默认值;
*/
defaultValue;
/**
* 字段是否只读;
*/
readonly;
}
注意:字段的 contentType 的格式参考 MIME Type 规范的格式,但并不是完全相同,支持和兼容类型请参考 字段的内容类型表
/**
* 工具按钮元数据;
*/
class ToolButtonMetadata {
/**
* 按钮显示的文本名称;
*/
name;
/**
* 按钮的唯一 key ;
*
* 当点击按钮触发事件时, key 会传递给事件相应函数;
*/
key;
/**
* 是否禁用按钮;
*/
disabled;
/**
* 图标;值可以是图标的组件名、样式表类名(class:// 前缀)、图标映射名(icon://)、图片 URL(http://或 https://);
*/
icon;
/**
* 路由的目标视图的名称;
*
* 如果定义了,则当菜单项被选择时,触发到指定视图的路由跳转;
*/
routeView;
/**
* 路由的目标路径;
*
* 如果定义了,则当菜单项被选择时,触发到指定路径的路由跳转;
*
* 当同时定义了 routeView 和 routePath 属性时,以 routePath 为高优先级而忽略 routeView ;
*/
routePath;
}
名称:数据视图元数据
说明: 用于定义 Grid 、 Form 等具备展示结构化数据能力的 UI 组件;
class DataViewMetadata {
/**
* 视图名称;
*
* 名称是数据视图的唯一标识;
*/
name;
/**
* 数据模型的类名;
*/
className;
/**
* 标题;
*/
title;
/**
* 字段元数据列表;
*
* 类型为 FieldMetadata[];
*
*/
fields;
}
/**
* 数据视图元数据中的字段元数据;
*
*/
class FieldMetadata {
/**
* 视图字段的唯一键;必须;
*/
key;
/**
* 视图字段对应的数据字段的key; 可选;
* 如果未设置则与 key 相同;
*/
dataKey;
/**
* 字段的显示名;可选;
*
* 如果未设置则采用 dataKey 对应的数据字段的名称属性(DataField.prototype.name);
*
* 如果未指定 dataKey 或者 dataKey 字段不存在,则以 key 值显示;
*/
name;
/**
* 是否只读;默认为 false;
*/
readonly;
}
/**
* 按钮点击事件;
*/
class ButtonClickEvent {
/**
* 按钮的 key;
*/
key;
/**
* 按钮的元数据;
*/
metadata;
}
类型 (Type) |
内容类型 (ContentType) |
参数 (Parameter) |
缺省默认 (Default When Missing) |
是否MIME (MIME) |
呈现形式 (Render Style) |
说明 |
---|---|---|---|---|---|---|
text | text/text | - | 是 | 否 | input 元素, type="text" | 单行原生字符,在表单中呈现为单行的文本输入控件 |
text/plain | - | - | 否 | input 元素, type="textarea" | 单行原生字符,在表单中呈现为多行的文本输入控件 | |
text/enum | key1=EnumName1;key2=EnumName2; 参数的“键”为枚举项的字符值,“值”为枚举项的名称。 | - | 否 | check / radio / select | 整数的枚举,读时呈现枚举名; 写时在表单中, 如果枚举项个数小于 5 ,对于单值则呈现为“radio 控件”,对于数组则呈现为“checkbox 控件”; 如果枚举项个数大于等于 5 ,则呈现为 “select 控件”,单值时为单选,数组时为多选。 |
|
text/password | - | - | 否 | input 元素, type="password" | 密码字符,在表单中呈现为密码输入控件 | |
text/email | - | - | 否 | input 元素, type="email" | 电子邮箱,在表单中呈现为电子邮箱地址输入控件 | |
text/tel | - | - | 否 | input 元素, type="tel" | 电话号码,在表单中呈现为电话号码输入控件 | |
text/JSON | - | - | 否 | input 元素, type="textarea" | JSON 字符,在表单中呈现为多行的文本输入控件 | |
timestamp | timestamp/datetime | - | 是 | 否 | datetime-picker | 时间戳,在表单中呈现为“日期时间输入控件” |
timestamp/date | - | - | 否 | date-picker | 时间戳,在表单中呈现为“日期输入控件” | |
timestamp/time | - | - | 否 | time-picker | 时间戳,在表单中呈现为“时间输入控件” | |
timestamp/mills | - | - | 否 | number | 时间戳,在表单中呈现为“数值输入控件”,数值表示毫秒值刻度。 | |
bool | bool/bool | - | 是 | 否 | checkbox | 布尔值,在表单中呈现为“checkbox控件” |
bool/options |
true=TrueOption '真'值选项的标签; false=FalseOption '假'值选项的标签; |
- | 否 | radio | 布尔值,在表单中呈现为“radio控件” | |
int | int/int | - | 是 | 否 | number | 整数,读时呈现数值,写时在表单中呈现为“数值控件”。 |
int/enum | 1=EnumName1;2=EnumName2; 参数的“键”为枚举项的数值,“值”为枚举项的名称。 | - | 否 | check / radio / select | 整数的枚举,读时呈现枚举名; 写时在表单中, 如果枚举项个数小于 5 ,对于单值则呈现为“radio 控件”,对于数组则呈现为“checkbox 控件”; 如果枚举项个数大于等于 5 ,则呈现为 “select 控件”,单值时为单选,数组时为多选。 |
|
bytes | bytes/bytes | encoding=base64 编码参数,默认为 base64; 可选值有:base58,hex,dec, oct, bin |
是 | 否 | input type="textarea" | 二进制数值;呈现为参数指定编码的字符串,在表单中写入时呈现为“多行文本输入控件”; 参数:hex(十六进制),dec(十进制), oct(8进制), bin(二进制) |
image/* | - | - | 否 | 读:image ; 写: input type="file" |
图片;读时呈现为图片,写时在表单中呈现为“文件上传控件”; 注:子类型表示图片的扩展名,如果为 '*' 则不过滤扩展名。 |
|
file/* | - | - | 否 | 读:a ; 写: input type="file" |
文件;读时呈现为文件下载的超链接,写时在表单中呈现为“文件上传控件”;如果为数组时呈现为多个下载链接或者多文件上传控件; 注:子类型表示图片的扩展名,如果为 '*' 则不过滤扩展名。 |
|
decimal | decimal/decimal | precision=8 精度参数,即保留的小数位数,默认为 8; | 是 | 否 | number | 小数;读时呈现数值,写时在表单中呈现为“数值控件”。 注:对于小数,平台自动实现精确计算。 |
decimal/currency |
precision=8 精度参数,即保留的小数位数,默认为 8; |
- | 否 | number | 货币;读时呈现数值,写时在表单中呈现为“数值控件”。 注:对于小数,平台自动实现精确计算。 |