前端视图的元数据与数据的传递、交互

在阅读本篇文章之前,您需要学习以下知识点:

1: 元数据

视图的元数据

在日常开发中,我们会经常遇到自定义的字段、动作、视图需要界面设计器配置的数据,这些数据可能是当前页面的字段,也有可能动作,那么如何获取呢?

视图元数据分为两种:
1: 当前视图(metadataRuntimeContext)
2: 根视图(rootRuntimeContext)

那么这两种类型怎么区分呢?

举个例子:
1: 如果当前字段是在表单中,那么当前视图就是表单,根视图就表单的父级视图,如果只有一个表单视图,那么当前视图就是根视图。
2: 如果当前视图是表单,但是表单里面有个表格,对于表格字段而言,当前视图就是表格,根视图就是表单。

当前视图的元数据(metadataRuntimeContext)

在前端,我们通过 metadataRuntimeContext 来获取视图的元数据,例如:

export class CustomFormStringFieldSingleWidget extends FormStringFieldSingleWidget {
  protected mounted(): void {
    console.log(this.metadataRuntimeContext);
  }

    /**
  * 界面设计器配置的动作
  */
  @Widget.Reactive()
  protected get modelActions() {
    return this.metadataRuntimeContext.model.modelActions
  }

   /**
  * 界面设计器配置的字段
  */
  @Widget.Reactive()
  protected get modelFields() {
    return this.metadataRuntimeContext.model.modelFields
  }
}
属性名 类型 可选性 描述
viewAction RuntimeViewAction 运行时跳转动作(通过跳转动作创建的运行时上下文具备该属性)
module RuntimeModule 运行时模块
model RuntimeModel 运行时模型
view RuntimeView 运行时视图
viewLayout DslDefinition \| undefined 视图布局 DSL,从运行时视图解析获得
viewDsl DslDefinition \| undefined 视图模板 DSL,从运行时视图解析获得
viewTemplate DslDefinition 视图最终执行 DSL,从运行时视图解析获得或根据布局 DSL 和模板 DSL 合并生成
getModel (model: string, isBelong?: boolean) => GetModelResult \| undefined 获取模型,返回获取的模型和所在的运行时上下文
getModelField (data: string, isBelong?: boolean) => GetModelFieldResult \| undefined 获取模型字段,返回获取的模型字段和所在的运行时上下文
getRequestModelFields (options?: GetRequestModelFieldsOptions) => RequestModelField[] 获取请求字段
getDefaultValue () => Promise<Record<string, unknown>> 获取默认值
getInitialValue () => Promise<Record<string, unknown>> 获取初始值

运行时模型(model)

属性名 类型 可选性 描述
id string 模型 id
model string 模型编码
name string 技术名称
modelFields RuntimeModelField[] 模型字段
modelActions RuntimeAction[] 模型动作
type ModelType 模型类型
module string 模块编码
moduleName string 模块名称
moduleDefinition RuntimeModule 模块定义
pks string[] 主键
uniques string[][] 唯一键
indexes string[][] 索引
sorting string 排序
label string 显示标题
labelFields string[] 标题字段

可通过modelFieldsmodelActions获取界面设计器配置的模型字段、模型动作。

当前视图的 dsl(viewDsl)

视图的 DSL,从运行时视图解析获得,如果模型中的modelFieldsmodelActions获取不到的对应的字段、动作,那么可从该属性中获取

默认值(getDefaultValue)

用来获字段的默认值(界面配置器配置的)

根视图的元数据(rootRuntimeContext)

根视图的元数据结构跟当前视图的元数据类似。

视图数据

视图数据是贯穿于应用程序前端和视图层的关键数据,它承载了应用逻辑到用户界面之间的桥梁作用。

在 oinone 前端中,常见的视图数据分为如下几种:

1: 表单数据(formData)
2: 列表数据(dataSource)
3: 根视图数据(rootData)
4: 当前字段、动作所在的区域数据(activeRecords)
5: 按钮打开弹窗、抽屉的时候,按钮所在的区域数据(openerActiveRecords)

formData

formData 是一个对象,对象中的每个属性对应一个表单项,表单项的值就是该属性的值。所有的表单字段都可以通过this.formData来访问,也可以通过this.formData.xxx来获取某个字段的值。

dataSource

dataSource 是一个数组,数组中的每个元素对应一个列表项,列表项的值就是该元素。所有的列表字段都可以通过this.dataSource来访问,也可以通过this.dataSource[0].xxx来获取某个列表字段的值。

rootData

rootData 是一个数组,如果当前视图是列表,那么 rootData 是列表的数据源。如果当前视图是表单,那么 rootData 是表单的数据源,其中的第 0 项是当前表单的数据。

activeRecords

activeRecords 是一个数组

1: 表单视图的动作
    1.1: activeRecords 是表单的数据源,其中的第 0 项是当前表单的数据。
2: 表格视图上方的动作
    2.1: activeRecords 是当前选中的行数据,其中的第 0 项是对应的数据。
3: 表格的行内动作
    3.1: activeRecords 是当前行数据,其中的第 0 项是对应的数据。

openerActiveRecords

openerActiveRecords 是一个数组,用于保存当前页面的 opener 页面选中的数据。

1: 比如 行内动作 点击打开弹窗,弹窗里面的字段或者动作可以通过 openerActiveRecords 获取 行内 数据.
2: 比如 表单中的动作 点击打开弹窗,弹窗里面的字段或者动作可以通过 openerActiveRecords 表单 数据.

特殊数据

activeTreeContext 树组件的选中数据

activeTreeContext 树组件的选中数据,可以获取到选中的数据,以及选中的数据的父级数据,用于左树右表的视图.

常见场景:

场景 1: 左树右表的视图,表格上方的创建按钮点击打开弹窗弹窗里面要获取左树选中的数据,用于创建数据.
方案:点击弹窗里面的创建按钮时,通过 this.metadataRuntimeContext.view?.activeTreeContext 获取到左树选中的数据

class CustomActon extends ServerActionWidget {
  protected async executeAction(action: RuntimeServerAction, submitValue: SubmitValue){
    const treeContext = this.metadataRuntimeContext.view?.activeTreeContext || {}
    submitValue.records = {
      ...submitValue.records,
      ...treeContext
    }
    super.executeAction(action, submitValue)
  }
}

场景 2: 左树右表的视图,表格上方的创建按钮点击打开新页面新页面里面要获取左树选中的数据,用于创建数据.
方案:点击新页面里面的创建按钮时,可通过URL参数获取到左树选中的数据

class CustomActon extends ServerActionWidget {
  protected async executeAction(action: RuntimeServerAction, submitValue: SubmitValue){
    const treeContext = JSON.parse(this.getUrlParameters().context).activeTreeContext || {}
    submitValue.records = {
      ...submitValue.records,
      ...treeContext
    }
    super.executeAction(action, submitValue)
  }
}

searchBody 搜索条件、searchConditions 固定查询条件

参考文章

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

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

Like (0)
汤乾华's avatar汤乾华数式员工
Previous 2024年10月8日 am10:37
Next 2024年10月8日 pm5:55

相关推荐

  • oio-switch 开关

    API 参数 说明 类型 默认值 版本 autofocus 组件自动获取焦点 boolean false checked(v-model: checked ) 指定当前是否选中 checkedValue | unCheckedValue false checkedChildren 选中时的内容 slot checkedValue 选中时的值 boolean | string | number true disabled 是否禁用 boolean false loading 加载中的开关 boolean false unCheckedChildren 非选中时的内容 slot unCheckedValue 非选中时的值 boolean | string | number false 事件 事件名称 说明 回调参数 change 变化时回调函数 Function(checked: boolean | string | number, event: Event)

    2023年12月18日
    1.4K00
  • 【前端】生产环境部署及性能调优

    概述 前端工程使用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.4K00
  • 前端自定义组件之多页面步骤条

    本文将讲解如何通过自定义,实现多页面的步骤条组件。其中每个步骤的元素里都对应界面设计器的一个页面。以下是代码实现和原理分析。 代码实现 NextStepWidget 多页面步骤条 ts 组件 import { CallChaining, createRuntimeContextByView, customMutation, customQuery, RuntimeView, SPI, ViewCache, Widget, DefaultTabsWidget, BasePackWidget } from '@oinone/kunlun-dependencies'; import { isEmpty } from 'lodash-es'; import { MyMetadataViewWidget } from './MyMetadataViewWidget'; import NextStep from './NextStep.vue'; import { IStepConfig, StepDirection } from './type'; @SPI.ClassFactory(BasePackWidget.Token({ widget: 'NextStep' })) export class NextStepWidget extends DefaultTabsWidget { public initialize(props) { this.titles = props.template?.widgets?.map((item) => item.title) || []; props.template && (props.template.widgets = []); super.initialize(props); this.setComponent(NextStep); return this; } @Widget.Reactive() public get invisible() { return false; } // 配置的每一步名称 @Widget.Reactive() public titles = []; // region 上一步下一步配置 // 步骤配置,切换的顺序就是数组的顺序,模型没有限制 @Widget.Reactive() public get stepJsonConfig() { let data = JSON.parse( this.getDsl().stepJsonConfig || '[{"model":"resource.ResourceCountry","viewName":"国家form"},{"model":"resource.ResourceProvince","viewName":"省form"},{"model":"resource.ResourceCity","viewName":"市form"}]' ); return data as IStepConfig[]; } // 切换上一步下一步 @Widget.Method() public async onStepChange(stepDirection: StepDirection) { // 没有激活的,说明是初始化,取第一步 if (!this.activeStepKey) { const step = this.stepJsonConfig[0]; if (step) { this.activeStepKey = `${step.model}_${step.viewName}`; await this.initStepView(step); } return; } // 获取当前步骤的索引 if (this.currentActiveKeyIndex > -1) { await this.onSave(); // 获取下一步索引 const nextStepIndex = stepDirection === StepDirection.NEXT ? this.currentActiveKeyIndex + 1 : this.currentActiveKeyIndex – 1; // 在索引范围内,则渲染视图 if (nextStepIndex >= 0 && nextStepIndex < this.stepJsonConfig.length) { const nextStep = this.stepJsonConfig[nextStepIndex];…

    2025年7月21日
    89800
  • 【动作】-路由动作跳转后如何主动刷新页面数据

    介绍 当我们使用多tab组件的时候,如果一个viewAction已经打开了一个tab页,再次用该viewAction打开页面的时候,会发现不会根据路由上的业务参数(如详情和编辑页的id参数)主动刷新数据,这个时候可以通过以下方法解决该问题 // 该方法可以在进入新路由页面后刷新数据,推荐将该方法放到工具类 function refreshViewAction(action: any) { const onRefreshTabWithActive = (manager: MultiTabsManager, instance: MultiTabInstance) => { // 进入路由后刷新页面数据 manager.refresh(instance.key); manager.clearOnActive(onRefreshTabWithActive); }; MultiTabsManager.INSTANCE.onActive(onRefreshTabWithActive); executeViewAction(action); } 将原本调用executeViewAction的方法改为refreshViewAction 如果需要扩展executeViewAction的其他入参请自行拓展refreshViewAction的入参

    2024年6月18日
    1.8K00
  • 【界面设计器】自定义字段组件实战——表格字段组合展示

    阅读之前 此文章为实战教程,已假定你熟悉了【界面设计器】较为完整的【自定义组件】相关内容。 如果在阅读过程中出现的部分概念无法理解,请自行学习相关内容。【前端】文章目录 业务背景 表格中的一列使用多个字段组合展示。 演示内容:表格中存在两列,【编码】和【基础信息】。将【名称】、【创建时间】、【更新时间】在【基础信息】一列展示。 业务分析及实现思路 从需求来看,我们需要实现一个【组合列】组件,并且该组件允许在【表格】视图中使用。由于【组合列】本身也是一个字段,因此这里需要选择需要组合字段中的其中一个字段作为组件切换的基础字段,比如我们可以选择【名称】字段作为基础字段。 在【组合列】组件的属性面板中,我们需要再自定义一个【组合列配置】组件,用来选择需要将哪些字段进行组合,以及为每个组合提供一些基础配置。 这里需要理解一个基本概念,即【组合列】的属性面板是【组合列配置】的【执行页面】。所有组件的属性面板在【执行页面】时都是【表单】视图。 因此我们可以实现一个【组合列配置】组件,并且该组件允许在【表单】视图中使用。其业务类型使用【文本】,我们在保存配置数据时,可以使用JSON数据结构来存储复杂结构。(这里的实现思路并非是最符合协议设定的,但可以满足绝大多数组件场景) 在【组合列配置】组件中,我们可以允许用户添加/移除组合,并且每个组合有两个属性,【标题】和【字段】。 准备工作 此处你应该已经在某个业务模型下,可以完整执行当前模型的全部【增删改查】操作。 业务模型定义 (以下仅展示本文章用到的模型字段,忽略其他无关字段。) 名称 API名称 业务类型 是否多值 长度(单值长度) 编码 code 文本 否 128 名称 name 文本 否 128 创建时间 createDate 日期时间 否 – 更新时间 updateDate 日期时间 否 – 实现页面效果展示 表格视图 创建组件、元件 准备工作完成后,我们需要根据【业务背景】确定【组件】以及【元件】相关信息,并在【界面设计器】中进行创建。 以下操作过程将省略详细步骤,仅展示可能需要确认的关键页面。 创建组合列组件 创建组合列元件 创建组合列配置组件 创建组合列配置元件 设计组合列元件属性面板 创建compositeConfig字段,并切换至【组合配置】组件。 设计组合列配置元件属性面板 启动SDK工程进行组件基本功能开发 PS:这里由于我们创建了两个组件,因此,将SDK分开下载后,然后将组合列配置SDK中的演示代码(kunlun-plugin/src)移动到组合列SDK中,在同一工程中进行开发,最后只需将相关JS文件和CSS文件上传到组合列组件中即可,组合列配置组件可以不进行上传。这里需要注意的是,上传多个包含相同组件功能的JS文件和CSS文件可能在运行时导致无法正常替换、冲突等问题。 (npm相关操作请自行查看SDK工程中内置的README.MD) 开发步骤参考 打开【表格】视图,将【名称】字段的组件切换为【组合列】组件。 在属性面板中看到【组合列配置】组件,并优先实现【组合列配置】组件。这里的属性面板就是【组合列配置】对应的【执行页面】。 当【组合列配置】组件可以按照预先设计的数据结构正确保存compositeConfig属性时,可以在【组合列】组件中的props定义中直接获取该属性,接下来就可以进行【组合列】组件的开发。 代码实现参考 工程结构 typing.ts export interface CompositeConfig { key: string; label?: string; field?: string; value?: string; } CompositeColumnConfig.vue <template> <div class="composite-column-config"> <oio-form v-for="item in list" :data="item" :key="item.key"> <oio-form-item label="标题" name="label"> <oio-input v-model:value="item.label" /> </oio-form-item> <oio-form-item label="字段" name="field"> <a-select class="oio-select" dropdownClassName="oio-select-dropdown" v-model:value="item.field" :options="fields" /> </oio-form-item> <oio-button type="link" @click="() => removeItem(item)">移除</oio-button> </oio-form> <oio-button type="primary" block @click="addItem">添加</oio-button> </div> </template> <script lang="ts"> import { uniqueKeyGenerator } from '@kunlun/dependencies'; import { WidgetInstance } from '@kunlun/ui-designer-dependencies'; import { OioButton, OioForm, OioFormItem, OioInput } from '@kunlun/vue-ui-antd'; import { Select as ASelect } from 'ant-design-vue'; import { computed, defineComponent, PropType, ref, watch } from 'vue'; import { CompositeConfig } from '../../typing'; export default defineComponent({ name: 'CompositeColumnConfig', components: { OioForm, OioFormItem, OioInput, OioButton, ASelect }, props: { currentInstance: { type:…

    2023年11月1日
    1.5K00

Leave a Reply

Please Login to Comment