优维低代码:Custom Templates 自定义模板

2023-11-06 12:59

本文主要是介绍优维低代码:Custom Templates 自定义模板,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

导语

优维低代码技术专栏,是一个全新的、技术为主的专栏,由优维技术委员会成员执笔,基于优维7年低代码技术研发及运维成果,主要介绍低代码相关的技术原理及架构逻辑,目的是给广大运维人提供一个技术交流与学习的平台。

连载第十六期

《高级指引:Custom Templates 自定义模板》

# 背景

在较早的 Legacy Templates 构件模板中(以下称 Legacy Templates),我们定义了一种使用 JavaScript Functions 定义的构件模板,这一层抽象在一定程度上封装了复杂的构件配置。

Legacy Templates 使用函数定义,因此拥有了高度灵活的动态展开能力。但函数定义使得框架无法将它们像普通构件一样地利用起来,因此受到了诸多限制,例如模板无法享受 Provider 刷新带动更新、无法对模板绑定事件处理、无法让用户编排一个自定义模板等等。

因此有必要设计一种自定义模板(以下称 Custom Templates),它使用静态结构声明(JSON or YAML),并且拥有普通构件的所有能力,以便在 Brick Next 中编排者可以像普通构件一样去使用它们。

# 原理

Custom Templates 的定义和 Storyboard 中的构件配置基本保持一致,可以在它内部配置多个构件,并且可以为这些构件配置插槽。在系统渲染该模板时,将按模板定义展开,并维护一份模板外部与模板内部的属性和事件等的的映射关系。

模板的展开过程如下图所示:

上图中 紫色边框 表示的是 Custom Template,模板在运行时按模板的定义被展开,绿色边框 的构件是模板内部定义好的构件,展开前的模板的 tools 插槽下的 橙色边框 的构件按模板定义被移植到了 basic-bricks.micro-view 的 toolbar 插槽中。并且模板构件的属性和事件等也会按模板定义映射到相关内部构件中。

# 示例

例如一个简单的模板定义:

# A custom template definition.name: "some-package.my-custom-template"bricks:  - brick: "basic-bricks.micro-view"    properties:      pageTitle: "My Awesome Page"    slots:      content:        type: "bricks"        bricks:          - brick: "my.awesome-brick"          - brick: "my.another-brick"            events:              something.happen:                action: "console.log"

在定义好 Custom Templates 后,它们可以像普通构件一样使用:

# A storyboard partial.brick: "some-package.my-custom-template"# All lifeCycles and other configs.lifeCycle: ...

Custom Templates 可以代理内部构件的属性、事件、插槽和方法,以此实现将 Storyboard 上为该模板配置的属性和事件等映射到模板内部的指定构件上。

例如以下包含 proxy 设置的模板定义:

# A custom template definition with proxy.name: "some-package.my-custom-template"proxy:  properties:    pageName:      ref: "micro-vew"      refProperty: "pageTitle"      # Set `refTransform` instead of `refProperty`, to transform a property.      # E.g.:      #   refTransform: {      #     pageTitle: '<% `${DATA.pageName} - Awesome Page` %>'      #   }      # Tips: the transformed source data is `{ [tplPropName] : tplPropValue }`.  events:    awesome.happen:      ref: "awesome-brick"      refEvent: "something.happen"  slots:    tools:      ref: "micro-view"      refSlot: "toolbar"      # Optional `refPosition` (number):      # Insert the slotted bricks to the specified position of inner brick slot.      # If `refPosition >= 0`, counts from the start.      # If `refPosition < 0`, counts from the end.      # The `refPosition` is relative to the slotted bricks specified in template definition.  methods:    tellAwesomeStories:      ref: "awesome-brick"      refMethod: "tellStories"bricks:  - brick: "basic-bricks.micro-view"    ref: "micro-view" # Notice here! The ref id should be unique inside a custom template.    slots:      content:        type: "bricks"        bricks:          - brick: "my.awesome-brick"            ref: "awesome-brick" # And another ref.            events:              inner.happen:                # Use `targetRef` to point to another brick inside a custom template.                targetRef: "micro-view"                method: "updateView"

在 Storyboard 中使用:​​​​​​​

# A storyboard partial.brick: "some-package.my-custom-template"properties:  pageName: "My Awesome Page"events:  awesome.happen:    action: "console.log"slots:  tools:    type: "bricks"    bricks: [...]

在该 Storyboard 中:

  • 模板的pageName属性将被映射到模板内部的 micro-view 的 pageTitle 属性上;

  • 模板内部的awesome-brick触发的something.happen将触发模板的 awesome.happen 事件;

  • 模板的 tools 插槽将被装载到模板内部的 micro-view 的 toolbar 插槽中;

  • 调用模板的 tellAwesomeStories 将实际调用模板内部的 awesome-brick 的 tellStories 方法。

# 将模板的一个属性映射到多个不同的内部构件属性

有时候我们期望将模板的一个属性映射到多个不同的内部构件属性上,这时我们可以配置 extraOneWayRefs:​​​​​​​

proxy:  properties:    pageName:      ref: "micro-vew"      refProperty: "pageTitle"      extraOneWayRefs:        - ref: "button"          refProperty: "buttonName"        - ref: "link"          refProperty: "linkName"

对于以上配置,模板对外的属性 pageName 除了映射到micro-view的pageTitle上,还会同时映射到 button 和 link 的对应属性上。

注意:正如该配置的名称所说,extraOneWayRefs 是单向的,如果直接变更其内部构件的属性不会向上反馈到模板上。

# 属性合并

有时候我们希望自定义模板代理的内部构件的属性可以进行数据合并,而不是整体的属性映射。例如我们定义一个自定义模板,它内部有一个表格构件,它的 columns 初始定义了一些通用列,同时希望编排者可以按需为表格增加其它的列定义。

现已支持通过 mergeProperty 等配置即可实现属性合并,例如定义一个自定义模板:​​​​​​

name: "tpl-extensible-table"proxy:  properties:    appendColumns:      ref: "table"      mergeProperty: "columns"      mergeType: "array" # "array" or "object"      mergeMethod: "append" # "append" or "prepend" or "insertAt"      # mergeArgs: # optional args for methods like "insertAt"bricks:  - brick: "presentational-bricks.brick-table"    properties:      # Predefined default columns      columns:        - dataIndex: "id"          title: "ID"        - dataIndex: "name"          title: "Name"

编排时:​​​​​​​

bricks:  - brick: "tpl-extensible-table"    properties:      # User-defined extra columns      appendColumns:        - dataIndex: "email"          title: "Email

详细说明:

  • mergeProperty: 要合并到的内部构件的属性名。

  • mergeType:

    支持两种类型:"array" 和 "object"。

  • mergeMethod:

    当mergeType === "array"时支持三种方法: "append", "prepend", "insertAt";

    当mergeType === "object" 时只支持一种方法:"extend"。

  • mergeArgs:

    当mergeType === "array" && mergeMethod === "insertAt" 时传入一个索引位置,位置为负数时,从结尾开始计数,默认为 [ -1 ]。

注意:当使用 mergeProperty 时,属性是从模板到内部构件单向流动的,即如果直接更改内部构件的相关属性,无法影响直接从模板读取的属性。

# 属性作为内部变量

有时候我们希望可以定义一些模板实例级别的变量,模板内部的构件可以在属性、事件等地方消费这些变量。注意它和 Context 上下文 的区别,后者相当于全局变量,无法将其作用域限制在某个具体的模板的实例内部。

现已支持将指定的模板属性标记为可供内部构件引用的变量,例如定义一个自定义模板:​​​​​​​

name: "tpl-flexible-table"proxy:  properties:    # 1. 将属性标记为 `asVariable: true`。    dataIndexOfName:      asVariable: truebricks:  - brick: "presentational-bricks.brick-table"    properties:      columns:        # 2. 在求值占位符中使用 `TPL.*` 引用标记好的属性。        - dataIndex: "<% TPL.dataIndexOfName ?? 'name' %>"          title: "Name"

编排时:​​​​​​​

bricks:  - brick: "tpl-flexible-table"    properties:      dataIndexOfName: "hostname"  - brick: "tpl-flexible-table"    properties:      dataIndexOfName: "username"

⊙ NOTE

在内部构件的属性中引用 TPL.* 时,只能在构件初始时拿到其初始值,此时该属性变量相当于一个常量,当模板实例的对应属性在运行时重新赋值时,该内部构件的属性不会发生变化。另一方面,在事件回调里则始终能拿到当事件发生时、最新的 TPL.*。更多信息请参考 Context 上下中的注意事项。

# 开发

  • 运行 yarn yo;

  • 选择 a new custom template (如果没有该选项,请先执行 yarn renew 然后再从第一步开始);

  • 输入你的 Custom Template 名称;

一个新的 Custom Template 就初始化好了:​​​​​​​

// `./bricks/YOUR-PKG/src/custom-templates/YOUR-TEMPLATE.ts`import { getRuntime } from "@next-core/brick-kit";
getRuntime().registerCustomTemplate("YOUR-PKG.YOUR-TEMPLATE", {  bricks: [],  proxy: {},});

这篇关于优维低代码:Custom Templates 自定义模板的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/356767

相关文章

SpringBoot中四种AOP实战应用场景及代码实现

《SpringBoot中四种AOP实战应用场景及代码实现》面向切面编程(AOP)是Spring框架的核心功能之一,它通过预编译和运行期动态代理实现程序功能的统一维护,在SpringBoot应用中,AO... 目录引言场景一:日志记录与性能监控业务需求实现方案使用示例扩展:MDC实现请求跟踪场景二:权限控制与

利用Python打造一个Excel记账模板

《利用Python打造一个Excel记账模板》这篇文章主要为大家详细介绍了如何使用Python打造一个超实用的Excel记账模板,可以帮助大家高效管理财务,迈向财富自由之路,感兴趣的小伙伴快跟随小编一... 目录设置预算百分比超支标红预警记账模板功能介绍基础记账预算管理可视化分析摸鱼时间理财法碎片时间利用财

如何在 Spring Boot 中实现 FreeMarker 模板

《如何在SpringBoot中实现FreeMarker模板》FreeMarker是一种功能强大、轻量级的模板引擎,用于在Java应用中生成动态文本输出(如HTML、XML、邮件内容等),本文... 目录什么是 FreeMarker 模板?在 Spring Boot 中实现 FreeMarker 模板1. 环

Spring Security自定义身份认证的实现方法

《SpringSecurity自定义身份认证的实现方法》:本文主要介绍SpringSecurity自定义身份认证的实现方法,下面对SpringSecurity的这三种自定义身份认证进行详细讲解,... 目录1.内存身份认证(1)创建配置类(2)验证内存身份认证2.JDBC身份认证(1)数据准备 (2)配置依

利用Python调试串口的示例代码

《利用Python调试串口的示例代码》在嵌入式开发、物联网设备调试过程中,串口通信是最基础的调试手段本文将带你用Python+ttkbootstrap打造一款高颜值、多功能的串口调试助手,需要的可以了... 目录概述:为什么需要专业的串口调试工具项目架构设计1.1 技术栈选型1.2 关键类说明1.3 线程模

Python Transformers库(NLP处理库)案例代码讲解

《PythonTransformers库(NLP处理库)案例代码讲解》本文介绍transformers库的全面讲解,包含基础知识、高级用法、案例代码及学习路径,内容经过组织,适合不同阶段的学习者,对... 目录一、基础知识1. Transformers 库简介2. 安装与环境配置3. 快速上手示例二、核心模

Java的栈与队列实现代码解析

《Java的栈与队列实现代码解析》栈是常见的线性数据结构,栈的特点是以先进后出的形式,后进先出,先进后出,分为栈底和栈顶,栈应用于内存的分配,表达式求值,存储临时的数据和方法的调用等,本文给大家介绍J... 目录栈的概念(Stack)栈的实现代码队列(Queue)模拟实现队列(双链表实现)循环队列(循环数组

IDEA自动生成注释模板的配置教程

《IDEA自动生成注释模板的配置教程》本文介绍了如何在IntelliJIDEA中配置类和方法的注释模板,包括自动生成项目名称、包名、日期和时间等内容,以及如何定制参数和返回值的注释格式,需要的朋友可以... 目录项目场景配置方法类注释模板定义类开头的注释步骤类注释效果方法注释模板定义方法开头的注释步骤方法注

使用Java将DOCX文档解析为Markdown文档的代码实现

《使用Java将DOCX文档解析为Markdown文档的代码实现》在现代文档处理中,Markdown(MD)因其简洁的语法和良好的可读性,逐渐成为开发者、技术写作者和内容创作者的首选格式,然而,许多文... 目录引言1. 工具和库介绍2. 安装依赖库3. 使用Apache POI解析DOCX文档4. 将解析

C++使用printf语句实现进制转换的示例代码

《C++使用printf语句实现进制转换的示例代码》在C语言中,printf函数可以直接实现部分进制转换功能,通过格式说明符(formatspecifier)快速输出不同进制的数值,下面给大家分享C+... 目录一、printf 原生支持的进制转换1. 十进制、八进制、十六进制转换2. 显示进制前缀3. 指