# 组件渲染

当组件初始化、修改属性、改变大小、修改过滤参数等操作时,都会触发组件渲染。

下图描述了用户、页面和组件之间的核心交互逻辑。

组件架构图

# 用户、页面和组件的交互行为

  • 设计器选中组件显示属性面板

用户选中组件时设计器会显示组件的属性面板。系统根据capabilities.json定义的属性和属性面板配置,显示当前选中组件的属性。

  • 设计器通过属性面板修改组件属性

用户通过属性面板修改组件属性后,系统会触发组件的render函数渲染组件。组件渲染时通过componentBuilder获取组件的属性。

  • 设计器预览

仪表板SuperPage这种所见即所得的模块在设计器中切换预览时,不会重新渲染组件,由于查看区域的视窗大小变化,会触发组件的render重新调整组件大小。

  • 改变页面大小

用户改变了页面的视窗大小后,页面会从画布开始逐层向下分发大小变化事件,通知每一个组件render

  • 修改过滤参数

当改变了模型过滤条件引用的参数自动过滤的组件值后,使用模型查询数据的组件,需要重新发起查询。页面会通知这些组件数据变化,如果组件是显示的,那么先发起查询,查询完成后通知组件render

# IVisualComponent

所有的扩展组件开发都需要实现IVisualComponent接口。实现类的名字和package.json中配置的visualClassName一致。

页面在初始化IVisualComponent时,会将其包装为一个BOComponentWrapperBOComponentWrapper提供渲染组件位置、大小、标题、背景等通用能力,并创建一个包含vc-bodyclass的div作为domParent传递给IVisualComponentrender函数作为IVisualComponent渲染的根DOM。

export class MyVisualComponent implements IVisualComponent {

    constructor(args: VisualComponentArgs) {
        //初始化创建组件时调用一次,初始化组件的基本信息
    }

    public render(args: VisualComponentRenderArgs): void | Promise<void> {
        //渲染组件,创建DOM结构,输出样式,绑定事件...
    }
}

# constructor

组件初始化时调用constructor。在构造函数中可以完成一些组件的初始化操作。

# VisualComponentArgs

  • visualObject,可视化页面对象,包含了一些通用服务
  • compBuilder,组件的属性和对象访问接口,可以获取到组件元数据,下级组件等

# render

组件初始化、数据变化、主题变化等操作时都会调用render函数。

# VisualComponentRenderArgs

  • domParent,组件的父DOM,组件的DOM结构应该都创建在该DOM内。
  • renderType,组件渲染类型,渲染时判断类型决定如何增量渲染。
  • viewPort,组件渲染的大小和位置信息。
  • dataViews,组件的数据对象,通过package.jsondataViewMappings配置的查询产生的查询结果。
  • viewMode,页面的查看模式,包括编辑、预览、查看。
  • modifiedInfo,组件的增量变化信息。组件在渲染时可以使用该信息进行增量渲染,不用每次都重新渲染整个组件。例如改变了组件的背景,传入的组件。

# updateType

名称 描述
None 0 无变化
Data 1 数据变化,dataViewsmodifiedInfo中包含了变化的信息
Theme 2 主题变化
ViewMode 4 切换预览
Resize 8 尺寸变化
Visible 16 显示隐藏变化
All 128 全量刷新

# modifiedInfo

# dispose

销毁组件,组件被删除时调用。默认组件会将IVisualComponent移除出domParent,如有额外的销毁逻辑,可实现该函数。

# 增量渲染组件大小变化

当组件所在父容器尺寸变化时(比如用户拖动了浏览器窗口的大小),会触发组件渲染,renderTypeComponentRenderType.Resize

如果组件本身就是自适应的,组件的尺寸变化时内部的DOM元素会自动重新布局,那么可以不处理该增量变化。

如果组件内部的布局需要由程序进行控制,比如用canvas绘制的图形,当组件尺寸变化时,canvas需要重新绘制,那么需要实现此函数。实现者可以简单的重新调用一下render函数,实现全量渲染,也可以按需自己实现更精细化的增量渲染机制。

export class MyVisualComponent implements IVisualComponent {

    public render(args: VisualComponentRenderArgs): void {
        let renderType = args.renderType;
        if (renderType & ComponentRenderType.Resize) {
            this.doResize();
        }
    }

    private doResize(): void {
        this.charts.resize();
    }
}

# 弹出组件

弹出组件在没有弹出时不输出DOM,通过调用组件方法显示和隐藏组件。

弹出组件在隐藏时应该不响应任何事件,当显示时才一次性更新组件为最新状态。

在设计器中,弹出组件显示成一个带名称的方块,双击编辑后显示一个占据整个画布的编辑区。

TODO 截图

以菜单组件为例。通过调用组件方法交互,设置show显示菜单,hide隐藏菜单。

{
    "name": "MyMenu",
    "popupComponent": true,
    "accessableMethods": [{
        "name": "show"
    }, {
        "name": "hide"
    }]
}
export class MyMenu implements IVisualComponent {

    private visible: boolean;

    private menu: Menu;

    public render(args: VisualComponentRenderArgs): void {
        if(!visible || !this.menu) {
            return;
        }
        //render menu when visible
    }

    public show(args: BOInvokeComponentMethodArgs): void {
        this.visible = true;
        let menu = this.menu;
        if (!menu) {
            menu = this.menu = new Menu();
        }
        //init items from data
        let items;
        menu.setItems(items);
        menu.showAt(event);
    }

    public hide(args: BOInvokeComponentMethodArgs): void {
        this.visible = false;
        this.menu?.hide();
    }
}

# 逻辑组件

逻辑组件不输出任何DOM元素,在render中执行程序逻辑,通常用于定时器等场景。

逻辑组件在初始化或数据变化时才调用render函数,不响应其它类型事件。

以定时器组件为例,页面全部加载完毕后开始计时,可以通过组件方法startstop开始和停止计时。

{
    "name": "MyTimer",
    "logicComponent": true,
    "accessableMethods": [{
        "name": "start"
    }, {
        "name": "stop"
    }]
}
export class MyTimer implements IVisualComponent {

    private stopped: boolean;

    public render(args: VisualComponentRenderArgs): void {
        this.start();
    }

    public start(args: BOInvokeComponentMethodArgs): void {
        this.stopped = false;
        // start timer
    }

    public stop(args: BOInvokeComponentMethodArgs): void {
        this.stopped = true;
    }
}
是否有帮助?
0条评论
评论