自定义组件之手动渲染任意视图(v4)

private metadataViewWidget: MetadataViewWidget | null | undefined;

private async renderCustomView(model: string, viewName: string, slotName?: string) {
  const view = await ViewCache.get(model, viewName);

  if (!view) {
    return;
  }

  if (this.metadataViewWidget) {
    this.metadataViewWidget.dispose();
    this.metadataViewWidget = null;
  }

  const metadataViewWidget = this.createWidget(MetadataViewWidget, slotName, {
    metadataHandle: this.metadataHandle,
    rootHandle: this.rootHandle,
    internal: true,
    inline: true,
    automatic: true
  });

  this.metadataViewWidget = metadataViewWidget;

  metadataViewWidget.initContextByView(view);

  this.forceUpdate();
}

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

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

(0)
张博昊的头像张博昊数式管理员
上一篇 2025年2月24日 pm4:32
下一篇 2025年3月10日 pm4:39

相关推荐

  • 页面出现中文乱码,该怎么解决?

    可能性1: 后端读取视图的xml解析时,由于系统缺少中文字体,导致解析后出现乱码,这种问题常见于采用docker镜像部署的情况,很多基础镜像不带中文字体。 解决方案:在物理系统或者docker镜像内安装中文字体 可能性2: win环境下未指定文件的编码类型 解决方案: 启动命令中加上-Dfile.encoding=UTF-8参数 # 示例命令 java -jar -Dfile.encoding=UTF-8 pamirs-demo-boot-1.0.0-SNAPSHOT.jar -Plifecycle=INSTALL

    2023年11月1日
    1.5K00
  • 组件SPI机制(v4)

    阅读之前 你应该: 了解DSL相关内容。母版-布局-DSL 渲染基础(v4) 组件SPI简介 不论是母版、布局还是DSL,所有定义在模板中的标签都是通过组件SPI机制获取到对应Class Component(ts)并继续执行渲染逻辑。 基本概念: 标签:xml中的标签,json中的dslNodeType属性。 Token组件:用于收集一组Class Component(ts)的基础组件。通常该基础组件包含了对应的一组基础能力(属性、函数等) 维度(dsl属性):用于从Token组件收集的所有Class Component(ts)组件中查找最佳匹配的参数。 组件SPI机制将通过指定维度按照有权重的最长路径匹配算法获取最佳匹配的组件。 组件注册到指定Token组件 以BaseFieldWidget这个SPIToken组件为例,可以用如下方式,注册一个可以被field标签处理的自定义组件: (以下示例仅仅为了体现SPI注册的维度,而并非实际业务中使用的组件代码) 注册一个String类型组件 维度: 视图类型:表单(FORM) 字段业务类型:String类型 说明: 该字段组件可以在表单(FORM)视图中使用 并且该字段的业务类型是String类型 @SPI.ClassFactory( BaseFieldWidget.Token({ viewType: ViewType.Form, ttype: ModelFieldType.String }) ) export class FormStringFieldWidget extends BaseFieldWidget { …… } 注册一个多值的String类型组件 维度: 视图类型:表单(FORM) 字段业务类型:String类型 是否多值:是 说明: 该字段组件可以在表单(FORM)视图中使用 并且该字段的业务类型是String类型 并且该字段为多值字段 @SPI.ClassFactory( BaseFieldWidget.Token({ viewType: ViewType.Form, ttype: ModelFieldType.String, multi: true }) ) export class FormStringMultiFieldWidget extends BaseFieldWidget { …… } 注册一个String类型的Hyperlinks组件 维度: 视图类型:表单(FORM) 字段业务类型:String类型 组件名称:Hyperlinks 说明: 该字段组件仅可以在表单(FORM)视图中使用 并且该字段的业务类型是String类型 并且组件名称必须指定为Hyperlinks @SPI.ClassFactory( BaseFieldWidget.Token({ viewType: ViewType.Form, ttype: ModelFieldType.String, widget: 'Hyperlinks' }) ) export class FormStringHyperlinksFieldWidget extends BaseFieldWidget { …… } 当上述组件全部按顺序注册在BaseFieldWidget这个SPIToken组件中时,将形成一个以BaseFieldWidget为根节点的树: “` mermaidgraph TDBaseFieldWidget —> FormStringFieldWidgetBaseFieldWidget —> FormStringMultiFieldWidgetFormStringFieldWidget —> FormStringHyperlinksFieldWidget“` 树的构建 上述形成的组件树实际并非真实的存储结构,真实的存储结构是通过维度进行存储的,如下图所示: (圆角矩形表示维度上的属性和值,矩形表示对应的组件) “` mermaidgraph TDviewType([viewType: ViewType.Form]) —>ttype([ttype: ModelFieldType.Strng]) —>multi([multi: true]) & widget([widget: &#039;Hyperlinks&#039;]) direction LRttype —> FormStringFieldWidgetmulti —> FormStringMultiFieldWidgetwidget —> FormStringHyperlinksFieldWidget“` 有权重的最长路径匹配 同样以上述BaseFieldWidget组件为例,该组件可用的维度有: viewType:ViewType[Enum] ttype:ModelFieldType[Enum] multi:[Boolean] widget:[String] model:[String] viewName:[String] name:[String] 当field标签被渲染时,我们会组装一个描述当前获取维度的对象: { "viewType": "FORM", "ttype": "STRING", "multi": false, "widget": "", // 在dsl中定义的任意值 "model": "", // 在dsl编译后自动填充 "viewName": "", // 当前视图名称 "name": "" // 字段的name属性,在dsl编译后自动填充 } 当我们需要使用FormStringHyperlinksFieldWidget这个组件时,我们在dsl中会使用如下方式定义: <view type="FORM" title="演示表单" name="演示模型form" model="demo.DemoModel"> <field data="name" widget="Hyperlinks" /> </view> 此时,我们虽然没有在dsl中定义维度中的其他信息,但在dsl返回到前端时,经过了后端编译填充了对应元数据相关属性,我们可以得到如下所示的对象: { "viewType": "FORM", "ttype": "STRING", "multi": false, "widget":…

    2023年11月1日
    1.2K00
  • 自定义表格支持合并或列、表头分组

    本文将讲解如何通过自定义实现表格支持单元格合并和表头分组。 点击下载对应的代码 在学习该文章之前,你需要先了解: 1: 自定义视图2: 自定义视图、字段只修改 UI,不修改数据和逻辑3: 自定义视图动态渲染界面设计器配置的视图、动作 1. 自定义 widget 创建自定义的 MergeTableWidget,用于支持合并单元格和表头分组。 // MergeTableWidget.ts import { BaseElementWidget, SPI, ViewType, TableWidget, Widget, DslRender } from '@kunlun/dependencies'; import MergeTable from './MergeTable.vue'; @SPI.ClassFactory( BaseElementWidget.Token({ viewType: ViewType.Table, widget: 'MergeTableWidget' }) ) export class MergeTableWidget extends TableWidget { public initialize(props) { super.initialize(props); this.setComponent(MergeTable); return this; } /** * 表格展示字段 */ @Widget.Reactive() public get currentModelFields() { return this.metadataRuntimeContext.model.modelFields.filter((f) => !f.invisible); } /** * 渲染行内动作VNode */ @Widget.Method() protected renderRowActionVNodes() { const table = this.metadataRuntimeContext.viewDsl!; const rowAction = table?.widgets.find((w) => w.slot === 'rowActions'); if (rowAction) { return rowAction.widgets.map((w) => DslRender.render(w)); } return null; } } 2. 创建对应的 Vue 组件 定义一个支持合并单元格与表头分组的 Vue 组件。 <!– MergeTable.vue –> <template> <vxe-table border height="500" :column-config="{ resizable: true }" :merge-cells="mergeCells" :data="showDataSource" @checkbox-change="checkboxChange" @checkbox-all="checkedAllChange" > <vxe-column type="checkbox" width="50"></vxe-column> <!– 渲染界面设计器配置的字段 –> <vxe-column v-for="field in currentModelFields" :key="field.name" :field="field.name" :title="field.label" ></vxe-column> <!– 表头分组 https://vxetable.cn/v4.6/#/table/base/group –> <vxe-colgroup title="更多信息"> <vxe-column field="role" title="Role"></vxe-column> <vxe-colgroup title="详细信息"> <vxe-column field="sex" title="Sex"></vxe-column> <vxe-column field="age" title="Age"></vxe-column> </vxe-colgroup> </vxe-colgroup> <vxe-column title="操作" width="120"> <template #default="{ row, $rowIndex }"> <!– 渲染界面设计器配置的行内动作 –> <row-action-render :renderRowActionVNodes="renderRowActionVNodes" :row="row" :rowIndex="$rowIndex" :parentHandle="currentHandle" ></row-action-render> </template> </vxe-column> </vxe-table> <!– 分页 –> <oio-pagination :pageSizeOptions="pageSizeOptions" :currentPage="pagination.current"…

    2025年1月9日
    1.9K00
  • 左树右表页面,点击表格的新建按钮,获取选中的树节点

    左树右表页面,点击表格的新建按钮,获取选中的树节点 通过自定义action的方式来实现 新建一个action文件TreeActionWidget.ts import { ActionType, ActionWidget, SPI, ViewActionTarget, RouterViewActionWidget } from '@kunlun/dependencies'; import { OioNotification } from '@kunlun/vue-ui-antd'; @SPI.ClassFactory( ActionWidget.Token({ actionType: [ActionType.View], target: [ViewActionTarget.Router], name: 'uiView0000000000079503' // action对应的name }) ) export class TreeActionWidget extends RouterViewActionWidget { protected async clickAction() { const context = this.rootRuntimeContext.view.context || {}; const activeTreeContext = context.activeTreeContext || null; if (!activeTreeContext) { // 没有选中左侧树 OioNotification.error('', '请选择左侧节点!'); } else { // 选中的时候 (this.action as any).context = activeTreeContext; // 执行原先的action逻辑 super.clickAction(); } } }

    2023年11月1日
    1.3K00
  • 上下文在字段和动作中的应用

    上下文在字段和动作中的应用 在业务场景中,常常需要在打开弹窗或跳转到新页面时携带当前页面数据。此时,我们需要配置相关「动作」中的上下文信息。 在 oinone 平台中,上下文主要分为以下三种: activeRecord:当前视图数据 rootRecord:主视图数据 openerRecord:触发弹窗的对象 参考文档:oinone内的主视图数据和当前视图数据使用介绍 activeRecord 表示当前视图的数据。例如,若动作配置在表单上,则指代当前表单的数据;若配置在 o2m、m2m 字段表格上,则指代选中的行数据。 rootRecord 表示根视图的数据。若当前视图是表单页,则代表表单的数据;若为表格页,则代表表格的数据。 openerRecord 表示触发弹窗的对象。例如,在弹窗内的字段或动作中,可通过 openerRecord 获取触发弹窗的信息。 这三者均为对象 (Object) 类型。 界面设计器配置 在 o2m、m2m 表格字段弹窗中携带当前视图数据 假设我们设计了一个包含 o2m、m2m 表格字段的表单页面。打开相关弹窗时,需将表单中的 code 数据传递至弹窗中。 选择相应的「动作」,如创建或添加。在右侧属性面板底部找到「上下文」,添加格式为对象 {} 的上下文信息。 以键值对的格式添加上下文信息:{code: rootRecord.code}。 设计弹窗时,将 code 字段拖入弹窗中。 完成设计后保存并发布。 大家可以看到,上下文中的key是 code,但是value是rootRecord.code,这里取的是rootRecord而不是activeRecord,因为我们上面讲过如果当前动作配置在o2m、m2m的字段表格上面,那么activeRecord就是表格选中的行,我们现在要取的是表单上的code字段,所以需要用rootRecord。 注意点:key需要是提交模型【前端视图】存在的字段才能传递。

    2023年11月8日
    2.7K10

Leave a Reply

登录后才能评论