自定义组件之手动渲染任意视图(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

相关推荐

  • 字段组件submit方法详解

    场景介绍 在日常开发调试表单页的过程中,细心的小伙伴应该注意到,视图内的数据(通过vue调试工具看到的formData就是视图的数据)和最终通过服务端动作提交的数据不总是一致的,本文将带领大家解开疑惑。 为什么会出现这种现象? 出现这种情况都是当前模型上有关联关系字段的场景,以多对一(M2O)场景为例,由于当前模型的关联关系字段是通过字段配置中的referenceFields属性和当前模型的relationFields属性进行关联的,所以提交数据的时候只需要拿到relationFields配置的字段就可以了,没有必要再去多拿关联关系字段本身的数据。 结合业务场景说明 这里以商品模型和类目模型举例,商品模型内有个类目的m2o字段category和对应的relationFields字段categoryId,数据提交到后端的时候前端默认会根据字段配置只获取categoryId,而category的整个对象都不会被提交。 package pro.shushi.pamirs.demo.api.model; import pro.shushi.pamirs.demo.api.model.DemoItemCategory; import pro.shushi.pamirs.meta.annotation.Field; import pro.shushi.pamirs.meta.annotation.Model; import pro.shushi.pamirs.meta.base.common.CodeModel; @Model.model(DemoItem.MODEL_MODEL) @Model(displayName = "测试商品") public class DemoItem extends CodeModel { private static final long serialVersionUID = -5104390780952631397L; public static final String MODEL_MODEL = "demo.DemoItem"; @Field.String @Field(displayName = "商品名称") private String name; @Field.Integer @Field(displayName = "类目ID") private Long categoryId; @Field.many2one @Field.Relation(relationFields = {"categoryId"}, referenceFields = {"id"}) @Field(displayName = "商品类目") private DemoItemCategory category; } 前端是如何处理数据的 前端的字段组件提供了submit()方法来让我们可以有就会在提交数据的时候改变数据。 // 字段组件基类 export class BaseFormItemWidget< Value = unknown, Props extends BaseFormItemWidgetProps = BaseFormItemWidgetProps > extends BaseDataWidget<Props> { /** * 数据提交的方法,例如:m2o字段user(假设其关系字段为userId)的值{id: 1, name: 'xxx'},但是实际后端数据只需要其中的id,所以用m2o对应的关系字段userId提交数据就可以了 * @param submitValue */ public submit(submitValue: SubmitValue): ReturnPromise<Record<string, unknown> | SubmitRelationValue | undefined> { return undefined; } } 这里先以FormStringFieldSingleWidget组件处理密码类型的字段讲解。密码一般在输入的时候是明文,为了提高提交到后端的安全性,可以将这个密码加密后再传到后端,后端再做进一步处理,这个场景中,视图中的密码和提交给后端的密码就出现了不一致的情况, @SPI.ClassFactory( BaseFieldWidget.Token({ viewType: [ViewType.Form, ViewType.Search], ttype: ModelFieldType.String }) ) export class FormStringFieldSingleWidget extends FormStringFieldWidget { public submit(submitValue: SubmitValue) { let finalValue = this.value; /** * 数据提交的时候,如果判断当前字段是否需要加密,需要加密的情况用encrypt函数做加密处理 */ if (this.crypto && finalValue) { finalValue = encrypt(finalValue); } return SubmitHandler.DEFAULT(this.field, this.itemName, submitValue, finalValue); } 注意:关系字段配置的透出字段只影响该字段的查询数据方法的返回值,不会因为此配置就在提交数据里加上这部分配置的字段 字段需要提交关联关系字段内的所有数据如何处理? 我们可以在自定义组件里覆写submit()方法,直接将this.value内的数据返回这里以覆写多对多m2m字段为例 import { BaseFieldWidget, FormM2MFieldSelectWidget, ModelFieldType, SPI, SubmitValue, ViewType } from '@kunlun/dependencies'; @SPI.ClassFactory( BaseFieldWidget.Token({ viewType: ViewType.Form, ttype: ModelFieldType.ManyToMany, widget: 'Select', model: 'xxx.yyyyy', name: 'fileName01',…

    2024年9月10日
    1.7K00
  • 【前端】生产环境部署及性能调优

    概述 前端工程使用vue-cli-service进行构建,生成dist静态资源目录,其中包括html、css、javascript以及其他项目中使用到的所有资源。 在生产环境中,我们通常使用Nginx开启访问服务,并定位其访问目录至dist目录下的index.html,以此来实现前端工程的访问。 不仅如此,为了使得前端发起请求时,可以正确访问到后端服务,也需要在nginx中配置相应的代理,使得访问过程在同域中进行,以达到Cookie共享的目的。 当然,服务部署的形式可以有多种,上述的部署方式也是较为常用的部署方式。 部署 使用production模式进行打包 使用dotenv-webpack插件启用process.env 配置chainWebpack调整资源加载顺序 使用thread-loader进行打包加速 性能调优 使用compression-webpack-plugin插件进行压缩打包 启用Nginx的gzip和gzip_static功能 使用OSS加速静态资源访问(可选) 使用production模式进行打包 在package.json中添加执行脚本 { "scripts": { "build": "vue-cli-service build –mode production" } } 执行打包命令 npm run build 使用dotenv-webpack插件启用process.env 参考资料 dotenv-webpack 在package.json中添加依赖或使用npm安装 { "devDependencies": { "dotenv-webpack": "1.7.0" } } npm install dotenv-webpack@1.7.0 –save-dev 在vue.config.js中添加配置 const Dotenv = require('dotenv-webpack'); module.exports = { publicPath: '/', productionSourceMap: false, lintOnSave: false, configureWebpack: { plugins: [ new Dotenv() ] } }; .env加载顺序 使用不同模式,加载的文件不同。文件按照从上到下依次加载。 development .env .env.development production .env .env.production 配置chainWebpack调整资源加载顺序 chainWebpack对资源加载顺序取决于name属性,而不是priority属性。如示例中的加载顺序为:chunk-a –> chunk-b –> chunk-c。 code>test属性决定其打包范围,但集合之间会自动去重。如chunk-a打包node_modules下所有内容,chunk-b打包node_modules/@kunlun下所有内容。因此在chunk-a中将不再包含node_modules/@kunlun中的内容。没有

    2024年4月19日
    1.3K00
  • 如何增加页面消息通知轮询的间隔或者关闭轮询

    场景 oinone的前端页面默认自带了消息通知功能,在顶部状态栏可以看到消息的查看入口,默认每隔5秒查询一次最新的消息,我们可以通过自定义消息组件增加该间隔或者是关闭轮询 示例代码 修改轮询间隔 import { MaskWidget, NotificationWidget, SPI } from '@kunlun/dependencies'; @SPI.ClassFactory(MaskWidget.Token({ widget: 'notification' })) export class DemoNotificationWidget extends NotificationWidget { /** * 轮询间隔时间,单位: 秒 * @protected */ protected msgDelay = 30000; } 关闭轮询 import { MaskWidget, NotificationWidget, SPI } from '@kunlun/dependencies'; @SPI.ClassFactory(MaskWidget.Token({ widget: 'notification' })) export class DemoNotificationWidget extends NotificationWidget { protected mounted() { super.mounted(); // 清除轮询的定时器 this.msgTimer && clearInterval(this.msgTimer); // 挂载后手动查询一次消息 this.getMsgTotal(); } }

    2024年8月20日
    1.5K00
  • 前端自定义组件之左右滑动

    本文将讲解如何通过自定义,实现容器内的左右两个元素,通过左右拖拽分隔线,灵活调整宽度。其中左右元素里的内容都是界面设计器拖出来的。 实现路径 1. 界面设计器拖出页面 我们界面设计器拖个布局容器,然后在左右容器里拖拽任意元素。完成后点击右上角九宫格,选中布局容器,填入组件 api 名称,作用是把布局容器切换成我们自定义的左右滑动组件,这里的 api 名称和自定义组件的 widget 对应。最后发布页面,并绑定菜单。 2. 组件实现 widget 组件重写了布局容器,核心函数 renderLeft、renderRight,通过 DslRender.render 方法渲染界面设计器拖拽的元素。 import { BasePackWidget, DefaultContainersWidget, DslDefinition, DslRender, SPI, Widget } from '@oinone/kunlun-dependencies'; import LeftRightSlide from './LeftRightSlide.vue'; // 拿到界面设计器配置的子容器元素 function fetchContainerChildren(widgets?: DslDefinition[], level = 3): DslDefinition[] { if (!widgets) { return []; } const children: DslDefinition[] = []; for (const widget of widgets) { if (widget.widget === 'container') { children.push(widget); } else if (level >= 1) { fetchContainerChildren(widget.widgets, level – 1).forEach((child) => children.push(child)); } } return children; } @SPI.ClassFactory(BasePackWidget.Token({ widget: 'LeftRightSlide' })) export class LeftRightSlideWidget extends DefaultContainersWidget { public initialize(props) { super.initialize(props); this.setComponent(LeftRightSlide); return this; } // 获取容器的子元素 public get containerChildren(): DslDefinition[] { return fetchContainerChildren(this.template?.widgets); } // 初始宽度配置 @Widget.Reactive() public get initialLeftWidth() { return this.getDsl().initialLeftWidth || 400; } // 最小左宽度配置 @Widget.Reactive() public get minLeftWidth() { return this.getDsl().minLeftWidth || 200; } // 最小右宽度配置 @Widget.Reactive() public get minRightWidth() { return this.getDsl().minRightWidth || 200; } // 根据容器子元素渲染左侧 @Widget.Method() public renderLeft() { // 把容器的第一个元素作为左侧 const containerLeft = this.containerChildren[0]; if (containerLeft) { return DslRender.render(containerLeft); } } // 根据容器子元素渲染右侧 @Widget.Method() public renderRight() { // 把容器的第二个元素作为右侧 const containerRight = this.containerChildren[1]; if…

    2025年7月8日
    4.4K00
  • 在前端视图添加自定义的区域块

    添加自定义区域块 平台提供了一系列默认的视图布局,可以帮助开发人员快速构建出复杂的企业应用系统。当然,我们可以使用自定义区域块来扩展表格、表单、画廊、树形等视图。 自定义区域块概述 平台视图布局都是通过XML配置实现的。在视图布局中,我们可以使用一些特定的元素标签来构建视图的表头、表单、搜索区域等部分。而自定义区域块,就是这些元素标签之外的部分。我们可以通过在视图布局的XML中添加自定义区域块,来扩展页面功能。 视图类型及相关元素 视图类型分为表格(TABLE)、表单(FORM)、画廊(GALLERY)、树形(TREE)等。不同类型的视图布局,包含的元素也有所不同。 下面是几种视图类型及其对应的元素: 表格:搜索区域、表格主体,其中表格主体包含了表格上面的动作、表格区域等部分。 表单:表单区域,包含了表单动作、表单区域等部分。 画廊:动作、卡片详细信息。 在表格页面添加自定义区域块 以下是一个示例,演示如何在表格页面顶部添加自定义区域块。 1. 修改视图布局XML 首先,我们需要修改表格视图的XML布局,添加自定义区域块元素标签。 <view type="TABLE"> <!– 这是搜索区域 –> <pack widget="group"> <view type="SEARCH"> <element widget="search" slot="search" slotSupport="field" /> </view> </pack> <!– 这是表格主体 –> <pack widget="group" slot="tableGroup"> <!– 在这里添加自定义区域块元素标签 –> <element widget="MyCustomElement"></element> <!– 这是表格上面的动作 –> <element widget="actionBar" slot="actionBar" slotSupport="action"> <xslot name="actions" slotSupport="action" /> </element> <!– 这是表格区域 –> <element widget="table" slot="table" slotSupport="field"> <element widget="expandColumn" slot="expandRow" /> <xslot name="fields" slotSupport="field" /> <element widget="rowActions" slot="rowActions" slotSupport="action" /> </element> </pack> </view> 在上述代码中,我们添加了一个名为MyCustomElement的元素标签。这将作为我们自定义区域块的容器。 2. 创建自定义Vue组件 接下来,我们需要创建一个Vue组件,并将其指定为自定义元素标签MyCustomElement的模板。 <template> <div> <!– 在这里编写自定义区域块的内容 –> <p>Hello, world!</p> </div> </template> <script lang="ts"> import { defineComponent } from 'vue'; export default defineComponent({ components: { }, props: [], setup(props) { return {}; } }); </script> 在上述代码中,我们定义了一个非常简单的Vue组件,它在页面上显示一个“Hello, world!”的文本信息。 3. 创建自定义Element Widget 为了使自定义Vue组件与XML布局文件关联起来,我们需要创建一个对应的Element Widget。 import { BaseElementWidget, SPI, BaseElementViewWidget, Widget, ViewMode, FormWidget, BaseElementWidgetProps } from '@kunlun/dependencies'; import MyCustomElement from './MyCustomElement.vue'; @SPI.ClassFactory(BaseElementWidget.Token({ widget: 'MyCustomElementWidget' })) export class MyCustomElementWidget extends BaseElementWidget { public initialize(props: BaseElementWidgetProps): this { super.initialize(props) this.setComponent(MyCustomElement) return this } } 在上述代码中,我们继承了BaseElementWidget类,并在其中指定了Vue组件MyCustomElement。这样,XML布局文件中的元素标签就能够正确地与Vue组件关联起来。 4. 注册视图布局 最后,我们需要将上述代码配置注册。具体而言,我们需要调用registerLayout方法来将XML布局文件、模块名和视图类型进行关联。 import { registerLayout, ViewType } from '@kunlun/dependencies'; registerLayout( `<view type="TABLE"> <pack widget="group"> <view type="SEARCH"> <element widget="search" slot="search" slotSupport="field" />…

    2023年11月1日
    2.8K00

Leave a Reply

登录后才能评论