组件数据交互基础(v4)

阅读之前

你应该:

组件数据交互概述

数据结构设计

数据结构分为三大类,列表(List)对象(Object)以及弹出层(Popup)

  • 列表(List):用于多条数据的展示,主要包括搜索(用户端)自定义条件(产品端)排序分页数据选中数据提交数据校验功能。
  • 对象(Object):用于单条数据的展示,主要包括数据提交数据校验功能。
  • 弹出层(Popup):用于在一块独立的空间展示对应类型的数据。

数据结构与对于的内置视图类型:

  • 列表(List):表格视图(TABLE)画廊视图(GALLERY)
  • 对象(Object):表单视图(FORM)详情视图(DETAIL)

数据交互设计原则

组件与组件之间的结构关系是独立的,组件与组件之间的数据是关联的。因此,数据交互整体采用“作用域隔离(View),行为互通(CallChaining),数据互通(ActiveRecords)”这样的基本原则进行设计。实现时,围绕不同视图类型定义了一类数据结构所需的基本属性。

在弹出层进行设计时,使用Submetadata的方式,将包括弹出层在内的所有组件包含在内,以形成新的作用域。

通用属性及方法

属性

  • rootData:根数据源
  • dataSource:当前数据源
  • activeRecords:当前激活数据源

为了在实现时包含所有数据结构,我们统一采用ActiveRecord[]类型为所有数据源的类型,这些数据源在不同类型的视图中表示不同的含义:

  • 列表(List):dataSource为列表当前数据源,activeRecords为列表中被选中的数据。特别的,showDataSource为当前展示的数据源,它是dataSource经过搜索、排序、分页等处理后的数据源,也是我们在组件中真正使用的数据源。
  • 对象(Object):daraSourceactiveRecords总是完全一致的,且长度永远为1。因此我们有时也在组件中定义formData属性,并提供默认实现:this.activeRecords?.[0] || {}

方法

  • reloadDataSource:重载当前数据源
  • reloadActiveRecords:重载当前激活数据源

由于底层实现并不能正确判断当前使用的数据类型,因此我们无法采用统一标准的数据源修改方法,这时候需要开发者们自行判断。

重载列表数据源
cosnt dataSource: ActiveRecord[] = 新的数据源
// 重载数据源
this.reloadDataSource(dataSource);
// 重置选中行
this.reloadActiveRecords([]);
重载表单数据源
cosnt dataSource: ActiveRecord[] = 新的数据源(数组中有且仅有一项)
// 重载数据源
this.reloadDataSource(dataSource);
// 此处必须保持相同引用
this.reloadActiveRecords(dataSource);

内置CallChaining(链式调用)

在自动化渲染过程中,我们通常无法明确知道当前组件子组件交互的具体情况,甚至我们在定义当前组件时,并不需要关心(某些情况下可能无法关心)子组件的具体情况。这也决定了我们无法在任何一个组件中完整定义所需的一切功能。

为了保证组件行为的一致性,我们需要某些行为在各个组件的实现需要做到组件自治。以表格视图为例:当view标签在挂载时,我们无法确定应该怎样正确的加载数据,因此,我们需要交给一个具体的element标签来完成这一功能。当element标签对应的组件发生变化时,只需按照既定的重载方式将数据源提交给view标签即可。

除了保证组件行为的一致性外,我们不能完全的信任第三方框架对组件生命周期的处理顺序。因此,我们还需要对组件行为进行进一步的有序处理。以表格视图为例:我们希望搜索视图(SEARCH)的处理总是在加载数据前就处理完成的,这样将可以保证我们加载数据可以正确处理搜索条件,而这一特性并不随着模板结构的变化而发生变化。

平台内置的CallChaining
  • mountedCallChaining:挂载时钩子;
  • refreshCallChaining:刷新时钩子;
  • submitCallChaining:提交时钩子;
  • validatorCallChaining:验证时钩子;
优先级常量
  • VIEW_WIDGET_PRIORITY(0):视图组件优先级
  • FETCH_DATA_WIDGET_PRIORITY(100):数据提供者组件优先级
  • SUBVIEW_WIDGET_PRIORITY(200):子视图组件优先级

未设置优先级的hook将最后执行,在通常情况下,你无需关心优先级的问题。

注意事项
  • CallChaining通常不需要手动初始化,仅需通过inject方式获取即可。
  • CallChaining的hook/unhook方法需要在组件生命周期的mounted/unmounted分别执行,如无特殊情况,一般通过this.path作为挂载钩子的唯一键。
字段组件中使用mountedCallChaing
@Widget.Reactive()
@Widget.Inject()
protected mountedCallChaining: CallChaining | undefined;

protected mountedProcess() {
  // 挂载时处理
}

protected mounted() {
  super.mounted();
  this.mountedCallChaining?.hook(this.path, () => {
    this.mountedProcess();
  });
}

protected unmounted() {
  super.unmounted();
  this.mountedCallChaining?.unhook(this.path);
}

字段组件mountedCallChaing并不是必须的,因此我们未进行内置处理。

一般的,当视图数据被加载完成时,字段组件formDatavalue等属性,将通过响应式自动获取对应的值,因此在大多数情况下是不需要使用这一特性的。

当我们需要对字段获取的值做进一步初始化处理时,我们将需要使用这一特性。例如TreeSelect组件,必须在初始化时填充树下拉所需的结构化数据,这样才能正确展示对应的值。

字段组件mounted方法被执行时,我们还未执行视图数据加载,因此,在我们无法在mounted方法中操作formDatavalue等属性,只有在mountedCallChainingview标签执行时,按照执行顺序,此时字段的mountedChaining将在视图数据被加载完成后执行。

数据源持有者和数据源提供者

在设计上,我们通常将view标签设计为数据源持有者,将element标签设计为数据源提供者

原则上,在一个视图中有且仅有一个数据源提供者。

即:当一个element标签的实现组件通过reloadDataSource方法view标签设置数据源,我们就称该实现组件为当前view标签数据源提供者view标签数据源持有者

provider/inject

阅读该章节需要理解vue的依赖注入原理

在实现上,我们通过provider/inject机制将上述通用属性/方法进行交替处理,就可以实现根据模板定义的结构进行隔离和共享功能。

例如dataSource属性的实现:

/**
 * 上级数据源
 * @protected
 */
@Widget.Reactive()
@Widget.Inject('dataSource')
protected parentDataSource: ActiveRecord[] | undefined;

/**
 * 当前数据源
 * @protected
 */
@Widget.Reactive()
private currentDataSource: ActiveRecord[] | null | undefined;

/**
 * 提供给下级的数据源
 * @protected
 */
@Widget.Reactive()
@Widget.Provide()
public get dataSource(): ActiveRecord[] | undefined {
  return this.currentDataSource || this.parentDataSource;
}

不足的是,由于provider/inject机制特性决定,通过provider提供的属性和方法,在某些情况下可能会进行穿透,导致组件通过inject获取的属性和方法并非是我们所期望的那样,因此,我们仍然需要进行一些特殊的处理,才能正确的处理子视图的数据交互,这一点在对象(Object)类型的视图中会详细介绍。

运行时上下文(metadataHandle/rootHandle)

在之前的文章中,我们知道前端的字段/动作组件渲染和后端元数据之间是密不可分的。

在数据交互方面,后端元数据对于字段类型的定义,将决定从API接口中获取的字段、数据类型和格式,以及通过API接口提交数据到后端时的字段、数据类型和格式

数据类型和格式可以通过field标签data属性,获取到经过后端编译的相关字段元数据。

那么,我们该如何决定,当数据提供者向后端发起请求时,应该获取哪些字段呢?

因此,我们设计了RuntimeContext机制,并通过metadataHandle/rootHandle机制,在任何一个组件都可以通过view标签正确获取已经实现隔离的运行时上下文机制。

以表单视图为例,我们来看这样一个经过合并后的完整视图模板:

(以下模板所展示的并非实际的运行时的结果,而是为了方便描述所提供的完整视图模板)

<view type="FORM">
    <element widget="actions">
        <action name="create" invisible="activeRecord.id" />
        <action name="update" invisible="!activeRecord.id" />
    </element>
    <element widget="fields">
        <field data="id" invisible="true" />
        <field data="code" />
        <field data="name" />
        <field data="relationOne" widget="Form">
            <view type="FORM">
                <element widget="form">
                    <field data="id" invisible="true" />
                    <field data="code" />
                    <field data="name" />
                </element>
            </view>
        </field>
        <field data="relationMany" widget="Table">
            <view type="TABLE">
                <element widget="actionBar">
                    <action name="openCreateDialog">
                        <view type="FORM">
                            <element widget="fields">
                                <field data="id" invisible="true" />
                                <field data="code" />
                                <field data="name" />
                            </element>
                        </view>
                    </action>
                </element>
                <element widget="table">
                    <field data="id" invisible="true" />
                    <field data="code" />
                    <field data="name" />
                    <element widget="rowActions">
                        <action name="openEditDialog">
                            <view type="FORM">
                                <element widget="fields">
                                    <field data="id" invisible="true" />
                                    <field data="code" />
                                    <field data="name" />
                                </element>
                            </view>
                        </action>
                    </element>
                </element>
            </view>
        </field>
    </element>
</view>

其中:

  • relationOne字段:代表M2O字段,它使用Form组件将字段展开为子表单视图。(O2O类型基本一致)
  • relationMany字段:代表O2M字段,它使用Table组件将字段展开为子表格视图。(M2M类型基本一致)
    • openCreateDialog:代表打开一个创建弹窗,它是一个上下文类型为上下文无关的跳转动作。
    • openEditDialog:代表打开一个编辑弹窗,它是一个上下文类型为单行的跳转动作。

PS:这里我们关注的是组件之间的数据交互,至于动作相关内容,我们会在其他文章中做进一步介绍。在这里我们只需要了解,当按钮的上下文类型为上下文无关时,该按钮将不会携带任何数据到下一个视图中;当按钮的上下文类型为单行时,该按钮将携带activeRecords[0]的数据到下一个视图中。

通过这个视图模板,我们将构建出如下图所示的RuntimeContext结构:

image.png

``` mermaid
graph TD
metadataHandle-1("metadataHandle-1(ViewAction)") ---> rootHandle-1("rootHandle-1(view type=#quot;FORM#quot;)")

rootHandle-1 ---> metadataHandle-2 & metadataHandle-3

metadataHandle-2("metadataHandle-2(field data=#quot;relationOne#quot;)") ---> rootHandle-2("rootHandle-2(view type=#quot;FORM#quot;)")
metadataHandle-3("metadataHandle-3(field data=#quot;relationMany#quot;)") ---> rootHandle-3("rootHandle-3(view type=#quot;TABLE#quot;)")

rootHandle-3 ---> metadataHandle-4 & metadataHandle-5

metadataHandle-4("metadataHandle-4(action name=#quot;openCreateDialog#quot;)") ---> rootHandle-4("rootHandle-4(view type=#quot;FORM#quot;)")
metadataHandle-5("metadataHandle-5(action name=#quot;openEditDialog#quot;)") ---> rootHandle-5("rootHandle-5(view type=#quot;FORM#quot;)")
```

由此可见,我们的metadataHandle可能通过页面入口(ViewAction)提供,也可能通过字段(field标签)提供,还可能通过动作(action标签)提供。无一例外的是,所有的view标签都将生成一个与之对应的rootHandle

在编码过程中,我们可以通过this.metadataRuntimeContextthis.rootRuntimeContext获取到对应的运行时上下文。前端运行时上下文API文档

列表(List)数据交互

对于列表(List)数据结构来说,我们目前提供了两种具体的视图:表格视图(TABLE)画廊视图(GALLERY),这两种视图分别对应不同的数据展示形态。

  • 表格视图(TABLE):字段代表表格中的列(Column),每一列的数据使用相同方式展示,无法使用布局特性。
  • 画廊视图(GALLERY):使用list - item形式进行渲染,每一个item可以通过DSL描述其布局特性。

特别的是,搜索视图(SEARCH)是对列表(List)数据结构提供搜索(用户端)相关功能的子视图,其独立存在于页面中是没有意义的。

默认表格视图(TABLE)

<view type="TABLE">
    <pack widget="group">
        <view type="SEARCH">
            <element widget="search" slot="search" />
        </view>
    </pack>
    <pack widget="group" slot="tableGroup">
        <element widget="actionBar" slot="actionBar">
            <xslot name="actions" />
        </element>
        <element widget="table" slot="table">
            <element widget="expandColumn" slot="expandRow" />
            <xslot name="fields" />
            <element widget="rowActions" slot="rowActions" />
        </element>
    </pack>
</view>

在之前的文章中,我们了解了布局和标签的基本概念,为了能更好的说明数据交互相关的特征,我们将上述视图进行简化,仅留下与数据交互相关的标签。

<view type="TABLE">
    <view type="SEARCH">
        <element widget="search" slot="search" />
    </view>
    <element widget="actionBar" slot="actionBar">
        <xslot name="actions" />
    </element>
    <element widget="table" slot="table">
        <xslot name="fields" />
        <element widget="rowActions" slot="rowActions" />
    </element>
</view>

在这个视图中,我们可以获得如下信息:

  • 主视图为表格(TABLE)视图。
  • 包含一个搜索(SEARCH)子视图。
  • 包含两个主要的element组件widget="actionBar"widget="table"
  • widget="table"中内置了一个element组件widget="rowActions"

在我们内置的组件实现中,widget="table"这个组件通过调用后端接口,为整个视图提供数据源。

组件挂载时序图

image.png

``` mermaid
sequenceDiagram

participant TableView as TableView("view type=#quot;TABLE#quot;")

participant SearchView as SearchView("view type=#quot;SEARCH#quot;")
participant Search as SearchWidget("element widget=#quot;search#quot;")

participant ActionBar as ActionBarWidget("element widget=#quot;actionBar#quot;")

participant Table as TableWidget("element widget=#quot;table#quot;")
participant RowActionBar as RowActionBarWidget("element widget=#quot;rowActions#quot;")

TableView ->> TableView : before mount
TableView ->> SearchView : before mount
SearchView ->> Search : before mount
TableView ->> ActionBar : before mount
TableView ->> Table : before mount
Table ->> RowActionBar : before mount

Search ->> SearchView : mounted
SearchView ->> TableView : mounted
ActionBar ->> TableView : mounted
RowActionBar ->> Table : mounted
Table ->> TableView : mounted
TableView ->> TableView : mounted

TableView ->> TableView : mountedCallChaing hook (VIEW_WIDGET_PRIORITY)

TableView ->> SearchView : mountedCallChaing hook (VIEW_WIDGET_PRIORITY)
SearchView ->> Search : mountedCallChaing hook (FETCH_DATA_WIDGET_PRIORITY)

TableView ->> Table : mountedCallChaing hook (FETCH_DATA_WIDGET_PRIORITY)

```

在上图中,我们可以看到,mountedCallChaining是在所有组件全部渲染并挂载完成后,通过最上层的view标签进行调用的,并且按照一定的优先级顺序执行了每个组件实现的挂载钩子函数

组件数据源加载

widget="search"组件执行了挂载钩子函数时,将从url参数中获取所需的searchBodysearchCondition属性,并通过flushSearchParameters方法将这两个参数提交到表格视图(TABLE)

widget="table"组件执行了挂载钩子函数时,将执行加载数据相关功能,并通过reloadDataSourcereloadActiveRecords方法对数据源进行向上提交。

image.png

``` mermaid
sequenceDiagram

participant TableView as TableView("view type=#quot;TABLE#quot;")

participant SearchView as SearchView("view type=#quot;SEARCH#quot;")
participant Search as SearchWidget("element widget=#quot;search#quot;")

participant Table as TableWidget("element widget=#quot;table#quot;")

TableView ->> SearchView : mountedCallChaing hook (VIEW_WIDGET_PRIORITY)
SearchView ->> Search : mountedCallChaing hook (FETCH_DATA_WIDGET_PRIORITY)
Search ->> Search : resolve url parameters
Search ->> SearchView : reloadActiveRecords
Search ->> TableView : flushSearchParameters

TableView ->> Table : mountedCallChaing hook (FETCH_DATA_WIDGET_PRIORITY)
Table ->> Table : mounted process (call api)
Table ->> TableView : reloadDataSource
Table ->> TableView : reloadActiveRecords

```

用户行为触发的数据交互

这里列举了一些列表(List)常用的数据交互时序图,用于帮助大家对数据交互的整体逻辑可以有更清晰的理解。

点击搜索

image.png

``` mermaid
sequenceDiagram

participant TableView as TableView("view type=#quot;TABLE#quot;")

participant SearchView as SearchView("view type=#quot;SEARCH#quot;")
participant Search as SearchWidget("element widget=#quot;search#quot;")

participant Table as TableWidget("element widget=#quot;table#quot;")

Search ->> TableView : flushSearchParameters
Search ->> SearchView : refreshCallChaining (call)
SearchView ->> TableView : refreshCallChaining (call)

TableView ->> Table : refreshCallChaining hook (FETCH_DATA_WIDGET_PRIORITY)
Table ->> Table : refresh process (call api)
Table ->> TableView : reloadDataSource
Table ->> TableView : reloadActiveRecords

```

排序/分页

image.png

``` mermaid
sequenceDiagram

participant TableView as TableView("view type=#quot;TABLE#quot;")

participant Table as TableWidget("element widget=#quot;table#quot;")

Table ->> Table : refresh process (call api)
Table ->> TableView : reloadDataSource
Table ->> TableView : reloadActiveRecords

```

表格勾选(table checkbox/radio)

image.png

``` mermaid
sequenceDiagram

participant TableView as TableView("view type=#quot;TABLE#quot;")

participant Table as TableWidget("element widget=#quot;table#quot;")

Table ->> TableView : reloadActiveRecords

```

对象(Object)数据交互

对于对象(Object)数据结构来说,我们目前提供了两种具体的视图:表单视图(FORM)详情视图(DETAIL),这两种视图分别对应不同的数据展示形态。

  • 表单视图(FORM):主要用于数据的填写和提交;可以通过DSL描述其布局特性。
  • 详情视图(DETAIL):主要用于数据的展示,所有字段强制为只读态(与表单的只读态有所不同);可以通过DSL描述其布局特性。

特别的是,表单视图(FORM)详情视图(DETAIL)在对子视图的处理上并不完全相同。主要体现在数据提交类型(submitType)关联关系更新类型(relationUpdateType)这两个属性的处理上。

数据提交类型(submitType)
/**
 * 数据提交类型
 */
export enum SubmitType {
  /**
   * <h3>默认</h3>
   * <p>
   * 基础字段使用全量提交,关联关系字段使用关联关系提交
   * </p>
   */
  default = 'default',
  /**
   * 不提交
   */
  none = 'none',
  /**
   * 关联关系字段关系提交(仅对关联关系字段有效)
   */
  relation = 'relation',
  /**
   * 关联关系字段增量提交(仅对关联关系字段有效)
   */
  increment = 'increment',
  /**
   * 全量提交
   */
  all = 'all'
}
关联关系更新类型(relationUpdateType)
/**
 * 关联关系数据更新类型
 */
export enum RelationUpdateType {
  /**
   * <h3>默认</h3>
   * <p>
   * 默认根据数据提交类型进行自动识别
   * </p>
   */
  default = 'default',
  /**
   * 使用特定接口进行差量更新(关联关系字段强制使用增量提交)
   */
  diff = 'diff',
  /**
   * 使用batch接口进行差量更新(关联关系字段强制使用增量提交)
   */
  batch = 'batch',
  /**
   * 全量更新
   */
  all = 'all'
}

下面分别列举了一些字段组件在不同视图中的默认功能。

表单视图(FORM)
组件 (widget) 一对一(O2O) 多对一(M2O) 一对多(O2M) 多对多(M2M)
Table / / 前端搜索、分页、排序
submitType="all"
relationUpdateType="all"
前端搜索、分页、排序
submitType="relation"
relationUpdateType="all"
Form submitType="all"
relationUpdateType="all"
submitType="all"
relationUpdateType="all"
/ /
Select submitType="relation"
relationUpdateType="all"
submitType="relation"
relationUpdateType="all"
submitType="relation"
relationUpdateType="all"
submitType="relation"
relationUpdateType="all"
详情视图(DETAIL)
组件 (widget) 一对一(O2O) 多对一(M2O) 一对多(O2M) 多对多(M2M)
Table / / 后端搜索、分页、排序
不支持数据提交
后端搜索、分页、排序
不支持数据提交
Form 仅用于查看
submitType="relation"
relationUpdateType="all"
仅用于查看
submitType="relation"
relationUpdateType="all"
/ /
Select 仅用于查看
submitType="relation"
relationUpdateType="all"
仅用于查看
submitType="relation"
relationUpdateType="all"
仅用于查看
submitType="relation"
relationUpdateType="all"
仅用于查看
submitType="relation"
relationUpdateType="all"

默认表单视图(FORM)

<view type="FORM">
    <element widget="actionBar" slot="actionBar">
        <xslot name="actions" />
    </element>
    <element widget="form" slot="form">
        <xslot name="fields" />
    </element>
</view>

在这个视图中,我们可以获得如下信息:

  • 主视图为表单(FORM)视图。
  • 包含两个主要的element组件widget="actionBar"widget="form"

在我们内置的组件实现中,widget="form"这个组件通过调用后端接口,为整个视图提供数据源。

组件挂载时序图

image.png

``` mermaid
sequenceDiagram

participant FormView as FormView("view type=#quot;FORM#quot;")

participant ActionBar as ActionBarWidget("element widget=#quot;actionBar#quot;")

participant Form as FormWidget("element widget=#quot;form#quot;")

FormView ->> FormView : before mount
FormView ->> ActionBar : before mount
FormView ->> Form : before mount

ActionBar ->> FormView : mounted
Form ->> FormView : mounted
FormView ->> FormView : mounted

FormView ->> FormView : mountedCallChaing hook (VIEW_WIDGET_PRIORITY)

FormView ->> Form : mountedCallChaing hook (FETCH_DATA_WIDGET_PRIORITY)

```

组件数据源加载

image.png

``` mermaid
sequenceDiagram

participant FormView as FormView("view type=#quot;FORM#quot;")

participant Form as FormWidget("element widget=#quot;form#quot;")

FormView ->> Form : mountedCallChaing hook (FETCH_DATA_WIDGET_PRIORITY)
Form ->> Form : mounted process (call api)
Form ->> FormView : reloadDataSource
Form ->> FormView : reloadActiveRecords

```

用户行为触发的数据交互

这里列举了一些对象(Object)常用的数据交互时序图,用于帮助大家对数据交互的整体逻辑可以有更清晰的理解。

点击提交动作(ServerAction)(创建/编辑)

image.png

``` mermaid
sequenceDiagram

participant FormView as FormView("view type=#quot;FORM#quot;")

participant Form as FormWidget("element widget=#quot;form#quot;")

participant ServerAction as ServerAction("action actionType=#quot;ServerAction#quot;")

ServerAction ->> FormView : submitCallChaining (call)
FormView ->> Form : submitCallChaining (call)
FormView ->> ServerAction : submitCallChaining (return)

ServerAction ->> ServerAction : execute action (call api)

```

Oinone社区 作者:oinone原创文章,如若转载,请注明出处:https://doc.oinone.top/frontend/26.html

访问Oinone官网:https://www.oinone.top获取数式Oinone低代码应用平台体验

(0)
oinone的头像oinone
上一篇 2023年6月20日 pm4:07
下一篇 2023年11月2日 pm1:58

相关推荐

  • 树型表格全量加载数据如何处理

    阅读该文档的前置条件 【界面设计器】树形表格 1.前端自定义表格组件 import { ActiveRecord, BaseElementWidget, Condition, Entity, SPI, TableWidget, ViewType } from '@kunlun/dependencies'; @SPI.ClassFactory( BaseElementWidget.Token({ type: ViewType.Table, widget: ['demo-tree-table'] }) ) export class TreeTableWidget extends TableWidget { // 默认展开所有层级 protected getTreeExpandAll() { return true; } // 关闭懒加载 protected getTreeLazy(): boolean { return false; } public async $$loadTreeNodes(condition?: Condition, currentRow?: ActiveRecord): Promise<Entity[]> { // 树表加载数据的方法,默认首次只查第一层的数据,这里去掉这个查询条件的参数condition,这样就会查所有层级数据 return super.$$loadTreeNodes(undefined, currentRow); } } 2. 注册layout import { registerLayout, ViewType } from '@kunlun/dependencies'; const install = () => { registerLayout( ` <view type="TABLE"> <element widget="actionBar" slot="actionBar" slotSupport="action"> <xslot name="actions" slotSupport="action" /> </element> <element widget="demo-tree-table" slot="table"> <element widget="expandColumn" slot="expandRow" /> <xslot name="fields" slotSupport="field" /> <element widget="rowActions" slot="rowActions" slotSupport="action" /> </element> </view> `, { viewType: ViewType.Table, model: "resource.resourceCity", // 变量,需要替换 actionName: "MenuuiMenu6f6005bdddba468bb2fb814a62fa83c6", // 变量,需要替换 } ); }; install();

    2024年8月17日
    73300
  • [前端]平台内置的基类

    前端平台内置了多个基类,允许开发者通过继承的方式来实现字段、视图以及动作。以下是一些常见的基类: 视图基类 通用视图基类 BaseElementWidget BaseElementWidget 是所有视图的通用基类,无论是何种视图,都可以继承这个基类。它封装了一系列属性和API,帮助开发者更轻松地创建各种视图组件。 表单类型的视图基类 BaseElementObjectViewWidget BaseElementObjectViewWidget 是表单视图的基类,它是BaseElementWidget的扩展。这个基类内部自动处理请求发起,以及数据刷新等一系列操作。 表格类型的视图基类 BaseElementListViewWidget BaseElementListViewWidget 是表格视图的基类,同样也是基于BaseElementWidget的扩展。它内部处理自动请求发起和数据刷新等操作,与BaseElementObjectViewWidget类似。 字段基类 表单字段基类 FormFieldWidget FormFieldWidget 是表单字段的基类,它封装了一系列属性和API,用于简化表单字段的开发。 表格字段基类 BaseTableFieldWidget BaseTableFieldWidget 是表格字段的基类,它封装了一系列属性和API,有助于开发者更轻松地创建表格字段。 动作基类 服务端动作基类 ServerActionWidget 跳转动作基类 RouterViewActionWidget 跳转动作基类(打开抽屉) DrawerViewActionWidget 跳转动作基类(打开抽屉) DrawerViewActionWidget 通过使用这些基类,开发者可以提高代码的可重用性和可维护性,从而更高效地开发前端应用。这些基类旨在帮助开发者更轻松地构建功能丰富的应用程序。

    2023年11月15日
    73100
  • oio-button 按钮

    主按钮:用于主行动点,一个操作区域只能有一个主按钮。 默认按钮:用于没有主次之分的一组行动点。 虚线按钮:常用于添加操作。 文本按钮:用于最次级的行动点。 链接按钮:一般用于链接,即导航至某位置。 以及四种状态属性与上面配合使用。 危险:删除/移动/修改权限等危险操作,一般需要二次确认。 禁用:行动点不可用的时候,一般需要文案解释。 加载中:用于异步操作等待反馈的时候,也可以避免多次提交。 API 按钮的属性说明如下: 属性 说明 类型 默认值 版本 block 将按钮宽度调整为其父宽度的选项 boolean false disabled 按钮失效状态 boolean false icon 设置按钮的图标类型 v-slot – loading 设置按钮载入状态 boolean | { delay: number } false type 设置按钮类型 primary | ghost | dashed | link | text | default default 事件 事件名称 说明 回调参数 版本 click 点击按钮时的回调 (event) => void 支持原生 button 的其他所有属性。

    2023年12月18日
    39200
  • 登录页自定义配置如何使用

    介绍 为满足大家对登录页面不同的展示需求,oinone在登录页面提供了丰富的配置项以支持大家在业务上的个性化需求 配置方式 在manifest.js内新增以下配置选项 manifest.js文件如何配置的参考文档 runtimeConfigResolve({ login: { /** * 登录按钮label */ loginLabel: '登录', /** * 是否显示忘记密码按钮 */ forgetPassword: true, /** * 忘记密码按钮Label */ forgetPasswordLabel: '忘记密码', /** * 是否显示注册按钮 */ register: true, /** * 注册按钮Label */ registerLabel: '注册', /** * 是否显示验证码登录Tab */ codeLogin: true, /** * 账号登录Tab Label */ accountLoginLabel: '账号', /** * 验证码登录Tab Label */ codeLoginLabel: '验证码', /** * 账号登录-账号输入框Placeholder */ accountPlaceholder: '请输入账号', /** * 账号登录-密码输入框Placeholder */ passwordPlaceholder: '前输入密码', /** * 验证码登录-手机号输入框Placeholder */ phonePlaceholder: '请输入手机号', /** * 验证码登录-验证码输入框Placeholder */ codePlaceholder: '请输入验证码', } });

    2024年4月24日
    91300
  • 【界面设计器】自定义字段组件基础

    阅读之前 本文档属于高阶实战文档,已假定你了解了所有必读文档中的全部内容,并了解过界面设计器的一些基本操作。 如果在阅读过程中出现的部分概念无法理解,请自行学习相关内容。【前端】文章目录 概述 平台提供的字段组件(以下简称组件)是通过SPI机制进行查找并最终渲染在页面中。虽然平台内置了众多组件,但无法避免的是,对于业务场景复杂多变的实际情况下,我们无法完全提供所有组件。 面对这样的困境,我们提供了外部注册组件的方式。在之前文章中,我们了解到组件注册后需要应用到页面中,需要配合DSL才能实现。其实,在平台中还提供了一种SAAS化的组件注册方式,配合界面设计器的设计能力,可以将组件在设计器页面中引入,从而更近一步的满足不同的业务场景。 通过界面设计器可以创建自定义组件,并为组件添加对应的元件。 界面设计器可以为元件设计其在指定视图下的属性面板,在页面设计时,可以使用该属性面板为元件设置相关属性。 在界面设计器的设计页面中拖入的组件,将通过SPI机制获取到一个唯一的元件,并渲染在页面中,提供给业务使用。 界面设计器-组件管理 名词解释 页面设计:使用界面设计器设计页面的页面。 属性面板设计:使用界面设计器设计属性面板的页面。 设计页面:页面设计和属性面板设计的统称。 组件库:展示在设计页面左侧的全部可拖拽组件。 组件:在组件库中可拖拽的最小单元。 元件:一个组件中的具体实现,是组件的最小单元。 属性面板:展示在设计页面右侧的元件属性。 页面设计 属性面板设计 组件管理入口 进入界面设计器后,可通过上方标签页切换至【组件】管理页面。 创建第一个组件 点击【添加组件】,在弹窗中输入组件名称【文本输入框】后,点击【确定】。 创建第一个元件 点击【组件卡片】或点击【管理元件】按钮进入【元件】管理页面。 点击【添加元件】,可以看到如下【创建元件】弹窗。 表单字段解释 元件名称:显示名称,仅在管理页面做展示使用。 API名称:SPI中的widget属性。 支持字段业务类型:SPI中的ttype属性。 支持多值:SPI中的multi属性。 支持视图类型:SPI中的viewType属性。 元件描述:元件功能描述内容,仅在管理页面做展示使用。 填入以下内容,并点击【确定】。 设计元件属性面板 点击【元件卡片】或点击【设计元件属性】按钮进入【属性面板设计】页面。 从【模型】中搜索【标题】,将【标题】和【隐藏标题】拖放至设计区域。如果想实现的相对美观,可以额外添加【分组】组件拖放至设计区域,并修改标题为【基础】,如下图所示。 点击【发布】按钮进行页面的发布。 至此,我们设计了第一个元件属性面板,接下来,我们需要在页面设计中使用这个组件。 在页面中使用【文本输入框】 由于我们之前选择的支持的视图类型是【表单】,因此我们在【表单】页面进行接下来的操作,此处略去创建视图的过程。 从【模型】中将【名称】拖放至设计区域。并通过点击【切换】按钮切换至我们的组件【文本输入框】,并且将标题改为【这是文本输入框组件】查看其展示效果。 属性变化 在组件切换后,属性面板发生了变化,原有属性会根据当前属性面板中现有字段进行【裁剪】,相同属性名称(字段)的值会被保留,其他属性值会被丢弃。 由于我们并没有在当前属性面板添加【宽度】属性,因此原有属性的宽度被丢弃,组件会自动变成默认【宽度】,默认宽度为1。 组件变化 由于我们并没有在【低无一体】中上传对应元件的代码实现,因此展示了默认的【单行文本】组件,目前组件的展示效果不会发生变化。 组件可切换规则 只有【组件】中包含与【当前选中字段】匹配的【元件】,才会将对应【组件】的名称展示在【可切换列表】中。 【当前选中字段】中包含了如下三个属性,这三个属性和【创建元件】时设置的属性一一对应。 (右侧属性面板切换至字段后,可查看当前选中字段的相关元数据信息。) 所在视图类型:根据字段在视图中的位置进行推断,当前所在位置为【表单】。当【支持视图类型】包含【表单】时条件成立。 字段业务类型:文本。当【支持字段业务类型】包含【文本】时条件成立。 是否多值:否。当【支持多值】相同时条件成立。 使用低无一体为组件上传代码实现 进入【组件】管理页面,点击【低无一体】,打开【低无一体】弹窗。 按照步骤,在【生成SDK】后,可以【下载模板工程】。在本地进行npm相关操作后,会在packages/kunlun-plugin目录下生成dist目录。在dist目录中,会有对应的kunlun-sdk.umd.js文件,使用【上传JS文件】进行上传。如果工程中包含了css,使用【上传CSS文件】进行上传。上传完成后点击【确定】进行保存。 PS:在模板工程中,我们提供了最简化的Hello World示例,即使不添加任何代码也可以看到组件的具体效果,为了方便演示,我们暂时不介绍代码实现的相关内容,仅需直接上传对应js文件,看到效果即可。如果遇到相关问题,请点击查看【前端】低无一体部署常见问题。 结语 至此,我们已经完整体验了从【创建组件】到【属性面板设计】再到【使用组件】以及【实现组件】的全部流程。 通过这一流程我们不难发现,【自定义组件】并非仅仅用于【页面设计】,在【属性面板设计】时,我们同样可以使用【自定义组件】来设计【自定义组件】的属性面板。这样便形成了一个完整的设计闭环,使得开发者可以更大程度的发挥自身创造力,开发出符合业务需求的【自定义组件】。

    2023年11月1日
    1.3K00

Leave a Reply

登录后才能评论