3.5.7.4 自定义页面

页面是什么

在Oinone前端体系中,页面是一个核心概念,它代表着终端用户所看到的当前视图。这个视图可以有多种形式,主要取决于页面是如何定义和构建的。在深入理解页面之前,我们需要了解两个关键的功能:自定义布局 和 自定义母版。

作用场景

自定义布局 提供了布局调整的强大功能,但在某些情况下,它可能无法完全满足特定的需求。这时,自定义页面就显得尤为重要。自定义页面是对 自定义布局 的补充,允许开发者从更深层次自由地控制和设计用户界面。

当标准布局无法实现所需的视觉效果或功能时,自定义页面提供了更高的灵活性。开发者可以通过自定义页面来实现独特的布局设计,添加特定的交互元素,或者整合复杂的业务逻辑,以创造独特且丰富的用户体验。

自定义页面

自定义视图组件允许开发者定义和使用特定于业务需求的视图布局。下面是一个具体的示例,展示了如何定义、注册和使用通过 setComponent 结合 TypeScript 和 Vue 的自定义视图组件。

示例工程目录

以下是需关注的工程目录示例,main.ts更新导入./view:

image.png

图3-5-7-48 自定义页面工程目录示例

1. 定义 TypeScript 组件

首先,我们定义了一个名为 CustomViewWidget 的 TypeScript 组件,并在该组件中通过 setComponent 结合 Vue 单文件组件。

import { BaseElementWidget, BaseElementViewWidget, SPI, ViewWidget } from '@kunlun/dependencies';
import CustomViewVue from './CustomView.vue';

@SPI.ClassFactory(BaseElementWidget.Token({ widget: 'CustomViewWidget' }))
  export class CustomViewWidget extends BaseElementViewWidget {
    public initialize(props) {
      super.initialize(props);
      this.setComponent(CustomViewVue);
      return this;
    }
  }

图3-5-7-49 定义TypeScript组件代码示例

2. Vue 单文件组件

其次,我们创建了对应的 Vue 单文件组件 CustomView.vue,用于展示自定义视图的具体内容。

<template>
  <div class="custom-view-wrapper">
    <h1>自定义视图</h1>
  </div>
</template>

<script lang="ts">
  import { defineComponent } from 'vue';

  export default defineComponent({
    inheritAttrs: false,
    name: 'ViewComponentVue'
  });
</script>

<style lang="scss">
  .custom-view-wrapper {}
</style>

图3-5-7-50 定义Vue组件代码示例

3. 注册自定义视图布局

接下来,我们使用 registerLayout 函数注册了一个表格视图布局,并在其中引入了通过 setComponent 结合的自定义视图组件。

import { registerLayout, ViewType } from "@kunlun/dependencies";

export const registerCustomView = () => {
  registerLayout(
    `
    <view type="TABLE">
      <element widget="CustomViewWidget" />
    </view>
    `,
    {
      viewType: ViewType.Table,
      moduleName: 'resource',
      model: 'resource.ResourceCountryGroup'
    }
  );
};

registerCustomView();

图3-5-7-51 注册自定义视图布局代码示例

效果

image.png

图3-5-7-52 自定义页面效果示例

4. 自定义视图在表格中的应用

当我们注册了自定义视图后,它就可以在表格视图中被使用。在表格视图的布局中,我们通过 标签将自定义视图嵌套在表格中,从而覆盖了表格的默认布局

5. 入参一致性

值得强调的是,registerLayout 函数和自定义布局的规则是一致的,这意味着开发者可以在自定义布局中使用与 registerLayout 相同的入参规则,从而实现更加灵活和统一的视图布局设计

与内置组件结合

1. 注册视图元素布局

首先,我们使用 registerLayout 函数注册了一个表格视图的布局。这个布局包含了搜索框、操作栏、以及一个自定义视图组件。

import { registerLayout, ViewType } from "@kunlun/dependencies";
import { CustomViewWidget } from "./CustomViewWidget";

export const registerViewElement = () => {
  registerLayout(
    `
    <view type="TABLE">
      <!-- 搜索和操作区域 -->
      <pack widget="group">
        <view type="SEARCH">
          <element widget="search" slot="search" slotSupport="field" />
        </view>
      </pack>

      <!-- 操作栏 -->
      <element widget="actionBar" slot="actionBar" slotSupport="action">
        <xslot name="actions" slotSupport="action" />
      </element>

      <!-- 自定义视图组件 -->
      <element widget="CustomViewWidget" />
    </view>
    `,
    {
      viewType: ViewType.Table,
      moduleName: 'resource',
      model: 'resource.ResourceCountry'
    }
  );
};

registerViewElement();

图3-5-7-53 注册视图布局代码示例

效果

image.png

图3-5-7-54 结合内置组件自定义页面效果示例

2. 视图布局结构说明

在这个布局中,我们使用了不同的标签来组织视图元素:

  • 标签用于组合多个元素为一个组。
  • 标签表示一个视图类型,这里包含了搜索框和操作栏。
  • 标签用于定义具体的元素,如搜索框和操作栏。
  • 标签引入了自定义视图组件 CustomViewWidget。

3. 视图元素的属性说明

通过传递相应的属性,我们定义了这个布局所属的视图类型(ViewType.Table)以及相关的模块和模型信息。

4. 自定义组件的使用

最后,我们展示了如何在表格视图布局中结合内置组件和自定义组件。这种设计灵活性高,可以根据具体业务需求定制各种复杂的视图。

使用元数据

1. 元数据的概念

元数据是描述数据的数据,它包含了关于数据的信息,如字段类型、验证规则、默认值等。在自定义页面中,元数据用于定义页面所需的数据结构、请求参数以及权限控制规则。

2. 元数据的收集

通过元数据的收集,我们可以获得当前页面所需的数据结构和相关请求参数的定义。这种方式避免了手动组装请求参数的繁琐过程,提高了开发效率。

3. 请求发起的效率提升

拥有了元数据,当前页面所在模型的所有请求可以直接使用收集到的元数据信息,无需手动组装请求参数。这不仅提升了请求发起的效率,还降低了出错的可能性。

4. 元数据在权限控制中的作用

元数据不仅用于请求发起,还在权限控制中发挥关键作用。通过元数据的信息,可以判断当前用户是否有权限查看、编辑或执行特定操作。这样避免了权限控制不生效的问题,确保系统的安全性和一致性。

5. 元数据元素的展示判断

在自定义页面中,如果使用了元数据元素作为页面的一部分,最好从收集中的元数据判断是否需要展示。这种方式确保了页面元素的显示与权限控制的一致性,有效地防止了未授权操作。

6. 最佳实践

  • 在自定义页面开发前,充分了解相关模型的元数据。

  • 利用元数据自动生成请求参数,提高开发效率。

  • 在页面渲染前,基于元数据进行权限判断,避免未授权操作。

7. 如何收集

使用 registerLayout 函数注册了一个自定义表格页面布局。在这个布局中,使用了 标签引入了自定义视图组件 CustomViewWidget,并通过 xslot 收集了操作和字段的元数据。

export const registerResolveModelView = () => {
    registerLayout(
        `
    <view type="TABLE">
      <element widget="CustomViewWidget" >
         <xslot name="actions" slotSupport="action" />
         <xslot name="fields" slotSupport="field" />
      </element>
    </view>
    `,
        {
            viewType: ViewType.Table,
            moduleName: 'resource',
            model: 'resource.ResourceCountry'
        }
    );
};

registerResolveModelView()

图3-5-7-55 xslot 收集操作和字段的元数据示例

8. 效果

没有xslot:

image.png

加入xslot:

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

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

(0)
史, 昂的头像史, 昂数式管理员
上一篇 2024年5月23日 am9:11
下一篇 2024年5月23日 am9:13

相关推荐

  • 3.5.7.2 自定义母版

    母版是什么 在业务系统中,母版是一种全局通用的组件,用于包裹每个页面的元素。这个概念类似于 PPT 中的母版,它定义了页面的整体结构、样式和布局,使得系统具有一致的外观和风格。 特点: 全局通用:母版是全局性的,适用于系统中的每个页面,确保一致性的用户体验。 包裹元素:母版包裹每个页面的元素,定义了整体的结构和布局。 外观一致性:通过统一的母版设计,系统达到外观和风格的一致性。 与 PPT 母版的类比: 在母版的概念上,与 PPT 中的母版类似,都是用于定义整体结构和样式,确保每个页面都具有一致的外观。 默认母版范围: 图3-5-7-20 默认母版范围 作用场景 在系统中,我们提供了多个纬度的母版,包括全局、应用和页面纬度。这样的设计允许根据不同的业务场景选择合适的母版纬度,以满足不同层次的定制需求。 母版纬度: 全局母版: 覆盖系统中所有页面,确保全局的一致性和统一的用户体验。 定义全局性的结构、样式和布局。 应用母版: 适用于特定应用或模块,定制化程度介于全局和页面之间。 允许在不同应用间实现一定的差异化。 页面母版: 面向具体页面,提供最大的定制化空间。 允许在不同页面中定义不同的结构和样式。 选择纬度: 业务场景决定:根据具体的业务场景和需求选择合适的母版纬度。 定制化需求:如果需要全局一致性,选择全局母版;如果在应用层面有特定需求,选择应用母版;如果需要最大的灵活性和定制化,选择页面母版。 参数说明: 在系统中,使用 registerMask 注册母版时,需要提供两个参数。第一个参数是母版的 XML,第二个参数用于控制母版的注册行为,包括 module、moduleName、model 和 actionName。 母版 XML(第一个参数): 提供母版的 XML 描述,定义了母版的结构和样式。 控制参数(第二个参数): module:指定模块的名称。 moduleName:指定模块的显示名称。 model:指定母版所属的模型。 actionName:指定母版的操作名称,可以是字符串或字符串数组。 全局母版 可以使用 registerMask 注册母版。当第二个参数为 {} 时,即代表注册全局母版。 示例工程目录 以下是需关注的工程目录示例,并确保导入导出依赖正确: 图3-5-7-21 全局纬度注册母版工程目录示例 示例代码 以下是一个示例代码: import { registerMask } from '@kunlun/dependencies'; /** * mask: 在做系统时,我们通常会把外层的布局(菜单、顶部导航)等抽出公共组件,公共组件会抽离全局通用。类似ppt母版的概念即为Mask * registerMask 第二个入参为{}即注册了全局得母版 * * 和默认母版相比移除右上角消息、语言切换、用户 * `<block> * <widget widget="notification" /> * <widget widget="divider" /> * <widget widget="language" /> * <widget widget="divider" /> * <widget widget="user" /> * </block>` */ const registerGlobalMask = () => { registerMask(` <mask> <multi-tabs /> <header> <widget widget="app-switcher" /> </header> <container> <sidebar> <widget widget="nav-menu" height="100%" /> </sidebar> <content> <breadcrumb /> <block width="100%"> <widget width="100%" widget="main-view" /> </block> </content> </container> </mask>`, {}); } registerGlobalMask(); 图3-5-7-22 全局纬度注册母版代码示例 复制这段代码执行下registerGlobalMask()试试看吧 效果 右上角消息、语言切换、用户被移除。 图3-5-7-23 全局纬度注册母版效果示例 应用母版 在系统中,可以使用 registerMask 注册母版。当第二个参数为 {moduleName: ‘resource’} 时,即注册了 resource(资源)应用的母版。 示例工程目录 以下是需关注的工程目录示例,更新导出./moduleMask: 图3-5-7-24 应用纬度注册母版工程目录示例 示例代码 以下是一个示例代码: /** * registerMask 第二个入参为{moduleName: 'resource'}即注册了resource(资源)应用的母版 * * resource来源: 通常是浏览器url上的module * * 和默认模版相比拿掉了菜单 * `<sidebar> * <widget widget="nav-menu" height="100%"…

    2024年5月23日
    1.2K00
  • 5.2 CDM之工程模式

    两种工程模式介绍 oinone推荐的两种工程模式都保留互联网特性,如跟业务无关的基础平台还是采用平台化思路建设。二种侧重点差异如下 第一种:比较适合企业采用多供应商联合开发场景,先以业务区分,各个业务线有独立的领域平台,最大限度保持不同业务线的独立性,有利于各个业务线独立发展(目前oinone上层星空系列产品采用这种工程模式,因为我们期望的时候帮助企业构建软件生态,必然要考虑不同供应商联合开发场景) 第二种:比较接近传统互联网架构,先按平台领域区分,如商品领域:商品平台做总工程,但里面按业务区分模块分子工程来保持业务相互独立,相对于第一种把领域的代码放一起,带来好处强化大家思考模型通用性。但不适用于跨公司主体间配合。 图5-2-1 Oinone-CDM的两种工程模式 注意事项: oinone兼容传统互联网架构 不管哪种模式,都需要解决CDM的维护问题 CDM维护的常见问题: Q:CDM层缺少模型怎么办? A:CDM层模型是逐步完善和丰富的。如果是特定业务自己需要的模型,这类模型无通用性。则加到自己的工程中;如果是通用的,则架构组确定是否需要纳入到CDM。 Q:CDM层已有的模型缺少字段怎么办? A:CDM层模型的字段也是逐步完善和丰富的,通用的字段在架构组确定后也会被吸收进来 Q:CDM层不同业务线相互影响怎么办? A:扩展字段最好带上自有前缀标志,如果觉得通用则提交架构组走模型缺少字段加入 Q:CDM层某模型新增加了的字段,但原先业务线已经加了相同含义字段 A:业务线可以把自己的字段related到CDM增加的新字段,并做数据迁移

    2024年5月23日
    89900
  • 3.2 Oinone以模块为组织

    模块(module):是按业务领域划分和管理的最小单元,是一组功能、界面的集合。 带大家快速认识下如何构建一个oinone的模块并启动它。我会从以下几个维度去介绍模块的构建与启动方式、模块详解。让大家直观且全方位地了解oinone的模块所包含的内容 构建第一个Module 启动前端工程 应用中心

    Oinone 7天入门到精通 2024年5月23日
    1.4K00
  • 4.1.14 Search之非存储字段条件

    search默认查询的是模型的queryPage函数,但我们有时候需要替换调用的函数,这个特性会在下个版本支持。其核心场景为当搜索条件中有非存储字段,如果直接用queryPage函数的rsql拼接就会报错,所以非存储字段不会增加在rsql中。本文介绍一个比较友好的临时替代方案。 非存储字段条件(举例) Step1 为PetTalent新增一个非存储字段unStore @Field(displayName = "非存储字段测试",store = NullableBoolEnum.FALSE) private String unStore; 图4-1-14-1 为PetTalent新增一个非存储字段unStore Step2 修改PetTalent的Table视图的Template 在标签内增加一个查询条件 <field data="unStore" /> 图4-1-14-2 修改PetTalent的Table视图的Template Step3 重启看效果 进入宠物达人列表页,在搜索框【非存储字段测试】输入查询内容,点击搜索跟无条件一致 Step4 修改PetTalentAction的queryPage方法 package pro.shushi.pamirs.demo.core.action; …… 引入依赖类 @Model.model(PetTalent.MODEL_MODEL) @Component public class PetTalentAction { ……其他代码 @Function.Advanced(type= FunctionTypeEnum.QUERY) @Function.fun(FunctionConstants.queryPage) @Function(openLevel = {FunctionOpenEnum.API}) public Pagination<PetTalent> queryPage(Pagination<PetTalent> page, IWrapper<PetTalent> queryWrapper){ QueryWrapper<PetTalent> queryWrapper1 = (QueryWrapper<PetTalent>) queryWrapper; Map<String, Object> queryData = queryWrapper.getQueryData(); String unStore = (String) queryData.get(LambdaUtil.fetchFieldName(PetTalent::getUnStore)); if (StringUtils.isNotEmpty(unStore)) { //转换查询条件 queryWrapper1.like( 图4-1-14-3 修改PetTalentAction的queryPage方法 Step5 重启看效果 在搜索框【非存储字段测试】输入查询内容,跟通过【达人】字段搜索的效果是一致的 图4-1-14-4 示例效果

    2024年5月23日
    89700

Leave a Reply

登录后才能评论