眺愤 发表于 2025-6-9 08:58:45

Util 应用框架 UI 全新升级

Util UI 已经开发多年, 并在多家公司的项目使用.
不过一直以来, Util UI 存在一些缺陷, 始终未能解决.
最近几个月, Util 团队下定决心, 终于彻底解决了所有已知缺陷.
Util 应用框架 UI 介绍

Util 应用框架 UI 建立在 Angular , Ng-Zorro, Ng-Alain 基础之上, 用于开发企业中后台.
Util 应用框架 UI 的特点


[*]简洁

Util UI 通常可以将复杂组件的 html 代码量压缩 3 - 10 倍,从而使项目的可维护性大幅提升.
下面以查询表单为例进行对比.
先看效果演示.

Util UI 的标签使用 TagHelper 进行封装 ,代码如下.
<util-card borderless="true" >
    <i nz-icon="" nzType="setting"></i><util-search-form label-width="120">
    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i><util-row gutter="24">
    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i><util-column>
    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i><util-input id="code" name="code"ng-model="queryParam.code" label-text="identity.application.code"/>
    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i></util-column>
    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i><util-column>
    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i><util-input id="name" name="name"ng-model="queryParam.name" label-text="identity.application.name"/>
    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i></util-column>
    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i><util-column>
    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i><util-select id="enabled" name="enabled"ng-model="queryParam.enabled" label-text="identity.application.enabled"/>
    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i></util-column>
    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i><util-column>
    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i><util-input id="remark" name="remark"ng-model="queryParam.remark" label-text="identity.application.remark"/>
    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i></util-column>
    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i><util-column>
    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i><util-column>
    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i><util-range-picker id="begin_creation_time" name="begin_creation_time"
    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>label-text="util.beginCreationTime"
    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>begin-date="queryParam.beginCreationTime" end-date="queryParam.endCreationTime"/>
    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i></util-column>
    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i><util-column>
    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i><util-range-picker id="begin_last_modification_time" name="begin_last_modification_time"
    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>label-text="util.beginLastModificationTime"
    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>begin-date="queryParam.beginLastModificationTime" end-date="queryParam.endLastModificationTime" />
    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i></util-column>
    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i><util-column >
    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i><util-flex justify="FlexEnd" align="Center" gap="Small">
    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i><util-button id="btnRefresh" icon="Sync" on-click="refresh(btnRefresh)" text-reset="true"></util-button>
    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i><util-button id="btnQuery" type="Primary" icon="Search" on-click="query(btnQuery)" text-query="true"></util-button>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>
    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i><util-a is-search="true" ></util-a>
    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i></util-flex>
    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i></util-column>
    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i></util-row>
    <i nz-icon="" nzType="setting"></i></util-search-form>
</util-card>上面的标签会转换成 Ng Zorro 原生的 html 标签.
    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>{{'identity.application.code'|i18n}}    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>{{'identity.application.name'|i18n}}    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>{{'identity.application.enabled'|i18n}}<util-card borderless="true" >
    <i nz-icon="" nzType="setting"></i><util-search-form label-width="120">
    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i><util-row gutter="24">
    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i><util-column>
    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i><util-input id="code" name="code"ng-model="queryParam.code" label-text="identity.application.code"/>
    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i></util-column>
    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i><util-column>
    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i><util-input id="name" name="name"ng-model="queryParam.name" label-text="identity.application.name"/>
    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i></util-column>
    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i><util-column>
    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i><util-select id="enabled" name="enabled"ng-model="queryParam.enabled" label-text="identity.application.enabled"/>
    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i></util-column>
    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i><util-column>
    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i><util-input id="remark" name="remark"ng-model="queryParam.remark" label-text="identity.application.remark"/>
    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i></util-column>
    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i><util-column>
    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i><util-column>
    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i><util-range-picker id="begin_creation_time" name="begin_creation_time"
    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>label-text="util.beginCreationTime"
    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>begin-date="queryParam.beginCreationTime" end-date="queryParam.endCreationTime"/>
    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i></util-column>
    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i><util-column>
    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i><util-range-picker id="begin_last_modification_time" name="begin_last_modification_time"
    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>label-text="util.beginLastModificationTime"
    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>begin-date="queryParam.beginLastModificationTime" end-date="queryParam.endLastModificationTime" />
    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i></util-column>
    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i><util-column >
    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i><util-flex justify="FlexEnd" align="Center" gap="Small">
    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i><util-button id="btnRefresh" icon="Sync" on-click="refresh(btnRefresh)" text-reset="true"></util-button>
    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i><util-button id="btnQuery" type="Primary" icon="Search" on-click="query(btnQuery)" text-query="true"></util-button>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>
    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i><util-a is-search="true" ></util-a>
    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i></util-flex>
    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i></util-column>
    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i></util-row>
    <i nz-icon="" nzType="setting"></i></util-search-form>
</util-card>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>{{'identity.application.remark'|i18n}}    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>{{'util.beginCreationTime'|i18n}}    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>{{'util.beginLastModificationTime'|i18n}}    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>{{'util.reset'|i18n}}    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>{{'util.query'|i18n}}    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>{{expand?('util.collapse'|i18n):('util.expand'|i18n)}}    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i> 是 Util UI 的查询表单标签.
查询表单支持响应式,并将按钮区域始终放置在最后一行的右侧.
label-width 是一个扩展的范围设置属性, 为每个表单组件的设置样式, 避免了分别设置每个组件的宽度.
Ng Zorro 表单组件由,,组合而成.
和设置了 label-text , 这是一个扩展属性,它会激活结构的自动创建.
是文本框, 除了为它自动创建结构, 还会添加清除内容的功能.
Util UI 大多常用组件的显示文本会自动添加 i18n 管道, 比如 'identity.application.code'|i18n ,用于支持多语言.
从前面的示例可以看到 Util UI 可以大幅提升 html 标签的书写效率, 降低维护成本.
[*]易用

Util 对常用功能进行了高度封装, 并提供简单易用的 API.
易用性是 Util UI 封装的关键目标,也是 Util UI 存在的意义.
本文后续将以最近更新的一个关键功能 - 表格设置, 演示易用性.
[*]强类型提示

Util UI 提供的标签使用 TagHelper 技术封装, 支持强类型提示.
如果你使用 Vs Code 开发, Util UI 标签提示信息大致与 Ng Zorro Vs Code 插件提示效果相当.
Vs Code 的标签提示信息并不精准, 包含很多与 html 相关的属性, 比如 aria- 打头的属性就占了几屏, 这降低了代码提示的作用.

如果使用 Vs 开发, 甚至安装了 Resharper , 代码提示就能达到最佳效果.

[*]持续更新和改进

Util UI 不仅仅是对 Ng Zorro 功能的简单包装, 更提供了常用功能的扩展.
Util UI 扩展功能来自之前使用其它 UI 框架的经验, 另外收集项目开发时的实际需求,并加以整理,以满足使用 Util UI 的项目.
Util 团队倾听开发人员的心声, 并持续改进, 从而更好的满足项目需求.
Util 应用框架 UI 的封装实现方式


[*]使用 .cshtml 替代 .html 页面.

.cshtml 是 .Net 提供的一种高级 html 封装技术.
Util 创造性的将 .cshtml 引入 Angular 应用开发.
Util 将 cshtml 页面作为 html 抽象层, 用来隐藏 html 的复杂性.
Ng Zorro 组件库定义了大量的 Angular 组件.
使用 Angular 组件, 就是在 html 页面中书写自定义的标签.
Util 应用框架使用 TagHelper 对 Ng Zorro 标签进行封装, 以提供更加简洁的用法.
TagHelper 是一种 .Net 标签, 在 .cshtml 文件中使用.
虽然 TagHelper 标签看上去也是一些自定义标签 , 但它们不是 Angular 组件.
Util 会在开发阶段将 .cshtml 文件转换成 html.
[*]使用 Angular 指令进行扩展.

Ng Zorro 组件库与 EasyUI 这样的组件库具有显著差异.
Ng Zorro 组件库提供的 API 具有粒度细, 扩展性强的特点.
Ng Zorro 组件的很多功能并不内置于组件中,而是通过 Demo 的形式告诉你怎么使用.
这为你提供了很大的灵活性和自由.
但也意味着,如果你不加封装,直接在项目中复制使用, 就会造成大量的冗余代码, 降低项目的可维护性.
要扩展 Ng Zorro 组件, 仅使用 TagHelper 封装 html 是不够的, 还需要找到编写脚本的地方.
封装和扩展 Ng Zorro 组件, 通常有两种方式.

[*]一种方式是创建新的 Angular 组件对原始组件进行包装.
使用组件包装, 可以提供更加易用的 Api.
不过这种封装方式也有一些缺陷.

[*]新组件的 API 与原始组件可能不同, 增加了学习成本.
[*]由于需要将原始组件的 API 暴露出来 , 导致更多的冗余代码.
[*]扩展性降低.
对于表格这样复杂的组件, html 结构相当复杂, 使用组件包装通常不会保留原有的 html 结构.
扩展点完全由新组件控制, 从而降低扩展性.

[*]另一种方式是使用 Angular 指令对原始组件进行扩展.
Angular 指令使用起来就像标签上的属性一样.
使用 Angular 指令进行扩展, 最大优势是保留原始组件的全部用法, 不会降低其扩展性.
当然指令封装方式也带来了新的挑战,那就是 html 标签会更加复杂.
Util UI 使用 Angular 指令进行封装扩展, 并使用 TagHelper 标签来隐藏 html 的复杂度.

[*]Lambda表达式支持

在 .cshtml 文件中使用 TagHelper 标签, 你可以直接设置标签上的属性.
不过 , 如果使用 .Net 开发 API 后端, 并创建了 DTO 对象, 你可以将 DTO 属性直接绑定到标签上.
下面演示查询表单组件如何使用Lambda表达式绑定 DTO 属性.
DTO 代码如下:
/// <summary>
/// 应用程序查询参数
/// </summary>
public class ApplicationQuery : QueryParameter {
    <i nz-icon="" nzType="setting"></i>/// <summary>
    <i nz-icon="" nzType="setting"></i>/// 应用程序编码
    <i nz-icon="" nzType="setting"></i>///</summary>
    <i nz-icon="" nzType="setting"></i>
    <i nz-icon="" nzType="setting"></i>public string Code { get; set; }
    <i nz-icon="" nzType="setting"></i>/// <summary>
    <i nz-icon="" nzType="setting"></i>/// 应用程序名称
    <i nz-icon="" nzType="setting"></i>///</summary>
    <i nz-icon="" nzType="setting"></i>
    <i nz-icon="" nzType="setting"></i>public string Name { get; set; }
    <i nz-icon="" nzType="setting"></i>/// <summary>
    <i nz-icon="" nzType="setting"></i>/// 启用
    <i nz-icon="" nzType="setting"></i>///</summary>
    <i nz-icon="" nzType="setting"></i>
    <i nz-icon="" nzType="setting"></i>public bool? Enabled { get; set; }
    <i nz-icon="" nzType="setting"></i>/// <summary>
    <i nz-icon="" nzType="setting"></i>/// 备注
    <i nz-icon="" nzType="setting"></i>///</summary>
    <i nz-icon="" nzType="setting"></i>
    <i nz-icon="" nzType="setting"></i>public string Remark { get; set; }
    <i nz-icon="" nzType="setting"></i>/// <summary>
    <i nz-icon="" nzType="setting"></i>/// 起始创建时间
    <i nz-icon="" nzType="setting"></i>/// </summary>
    <i nz-icon="" nzType="setting"></i>
    <i nz-icon="" nzType="setting"></i>public DateTime? BeginCreationTime { get; set; }
    <i nz-icon="" nzType="setting"></i>/// <summary>
    <i nz-icon="" nzType="setting"></i>/// 结束创建时间
    <i nz-icon="" nzType="setting"></i>/// </summary>
    <i nz-icon="" nzType="setting"></i>
    <i nz-icon="" nzType="setting"></i>public DateTime? EndCreationTime { get; set; }
    <i nz-icon="" nzType="setting"></i>/// <summary>
    <i nz-icon="" nzType="setting"></i>/// 起始最后修改时间
    <i nz-icon="" nzType="setting"></i>/// </summary>
    <i nz-icon="" nzType="setting"></i>
    <i nz-icon="" nzType="setting"></i>public DateTime? BeginLastModificationTime { get; set; }
    <i nz-icon="" nzType="setting"></i>/// <summary>
    <i nz-icon="" nzType="setting"></i>/// 结束最后修改时间
    <i nz-icon="" nzType="setting"></i>/// </summary>
    <i nz-icon="" nzType="setting"></i>
    <i nz-icon="" nzType="setting"></i>public DateTime? EndLastModificationTime { get; set; }
}.cshtml 代码如下:
@model ApplicationQuery<util-card borderless="true" >
    <i nz-icon="" nzType="setting"></i><util-search-form label-width="120">
    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i><util-row gutter="24">
    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i><util-column>
    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i><util-input id="code" name="code"ng-model="queryParam.code" label-text="identity.application.code"/>
    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i></util-column>
    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i><util-column>
    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i><util-input id="name" name="name"ng-model="queryParam.name" label-text="identity.application.name"/>
    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i></util-column>
    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i><util-column>
    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i><util-select id="enabled" name="enabled"ng-model="queryParam.enabled" label-text="identity.application.enabled"/>
    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i></util-column>
    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i><util-column>
    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i><util-input id="remark" name="remark"ng-model="queryParam.remark" label-text="identity.application.remark"/>
    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i></util-column>
    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i><util-column>
    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i><util-column>
    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i><util-range-picker id="begin_creation_time" name="begin_creation_time"
    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>label-text="util.beginCreationTime"
    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>begin-date="queryParam.beginCreationTime" end-date="queryParam.endCreationTime"/>
    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i></util-column>
    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i><util-column>
    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i><util-range-picker id="begin_last_modification_time" name="begin_last_modification_time"
    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>label-text="util.beginLastModificationTime"
    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>begin-date="queryParam.beginLastModificationTime" end-date="queryParam.endLastModificationTime" />
    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i></util-column>
    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i><util-column >
    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i><util-flex justify="FlexEnd" align="Center" gap="Small">
    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i><util-button id="btnRefresh" icon="Sync" on-click="refresh(btnRefresh)" text-reset="true"></util-button>
    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i><util-button id="btnQuery" type="Primary" icon="Search" on-click="query(btnQuery)" text-query="true"></util-button>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>
    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i><util-a is-search="true" ></util-a>
    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i></util-flex>
    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i></util-column>
    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i></util-row>
    <i nz-icon="" nzType="setting"></i></util-search-form>
</util-card>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>Lambda表达式会读取 DTO 对象的元数据, 并自动设置常用属性, 从而再次大幅提升生产力.
Util 应用框架 UI 的组成


[*]Util.Ui.NgZorro

Util.Ui.NgZorro 类库包含 Ng Zorro TagHelper 标签, 目前已封装官方正式发布的全部组件.
[*]Util.Ui.NgAlain

Util.Ui.NgAlain 类库包含 Ng Alain 部分组件 TagHelper 标签.
[*]util-angular

util-angular 是一个 typescript 脚本库, 包含 Ng Zorro 扩展指令和常用操作 Helper.
Util 应用框架 UI 最新进展

Util 应用框架 UI 最近进行了全面改进,并取得了重大突破.
最大的进展有2点, 一是开发机制的改进, 二是增加了表格设置功能.

[*]开发机制改进

[*]架构缺陷

Util 应用框架将 .cshtml 文件引入 Angular 已有相当长的年头.
由于这种非主流的用法并没有微软官方的支持,所以一直存在相当多的问题.

[*]最主要的影响是导致开发阶段运行缓慢.
之前的开发流程, Angular 组件在开发阶段直接访问 cshtml 页面,所以开发阶段必须使用 Angular JIT 模式, 它比 Angular AOT 模式要慢一些.
cshtml 在第一次访问时, 尚未创建缓存 , 会比较慢.
Angular 应用启动时,将访问根模块引用的所有页面, 所以启动时会产生相当的卡顿.
这个问题通过 Angular 延迟加载模块得到缓解.
如果项目比较大,包含数十个业务模块, 将每个业务模块创建为延迟加载模块.
当应用启动时, 并不会访问所有页面, 只有请求了某个业务模块的功能, 才会访问该模块包含的 cshtml 页面.
不过从 Angular 13 开始, Angular 移除了传统的视图引擎, 导致上述开发方式无法使用延迟加载模块.
这意味着所有业务模块在开发阶段必须在根模块中引用.
Angular 应用启动后将访问所有 cshtml 页面, 这显然是不可接受的.
一种可行的解决办法是使用微前端方案.
微前端架构将业务模块分离到不同的项目从而减少应用启动时间.
一些较大的项目和团队使用微前端架构是合适的.
但微前端架构具有复杂性, 使用微前端架构代替延迟加载模块则非常牵强.
这是 Util 团队进行全面改造的根本原因.
[*]另一个影响是项目结构比较复杂.
Util 采用的项目结构最早来自 .Net Core Angular 项目模板, 并加以修改.
Angular 应用被放在 ClientApp 目录中.
.cshtml 文件则被放在 Pages 目录中.
这导致组件与模板的对应关系比较复杂.

[*]改进方案

很多时候, 解决问题最重要是思路的转变.
之前的架构缺陷主要来自在开发阶段让 Angular 组件直接请求 cshtml 页面,从而与原生 Angular 应用产生差别.
不过, Util 使用 cshtml 仅限于开发阶段, 发布之后实际上与 cshtml 没有任何关系.
cshtml 的作用只是帮助生成 html 而已.
现代化开发一个重要的功能是热更新, 比如 Angular 应用, 它会持续监视你的相关文件.
当你编辑完 .ts 或 .html 文件时, 浏览器就会自动刷新.
如果我们监视所有 .cshtml 文件,并在保存 cshtml 文件时自动生成对应的 html 文件,就能从根本上解决问题.
由于只需要处理保存的 cshtml 文件, 生成 html 的速度将非常迅速.
当 html 生成完成, 后续流程则与原生 angular 应用相同, 从而解决引入 cshtml 相关的所有缺陷.
现在, 编辑并保存 .cshtml 文件, 浏览器就会自动刷新, 与原生 Angular 应用相比, 大致慢几百毫秒, 通常可以忽略不计.
项目结构复杂的问题则很好解决, 将 .cshtml 与 Angular 组件放在一起即可.
这与原生 Angular 应用相似, 只需修改 .cshtml 生成 html 文件的路径规则.
一直以来, Util UI的架构比较臃肿, 只能在 Vs 中开发.
但现在前端基本都使用 Vs Code.
最新 UI 架构与原生 Angular 应用差别很小, 同样适合使用 Vs Code 开发.
下面是使用 Vs Code 打开的项目结构.


[*]表格设置

表格是业务系统的基石.
我们收集了一些项目上使用 Ng Zorro 表格的反馈意见.

[*]当表格列较多时,如果不进行宽度设置, 则会显示得很畸形.
要解决这个问题, 需要设置表格 nzScroll 属性的 x 值.
nzScroll 的 x 可以让表格产生横向的滚动条, 从而将表格内容拉伸.
不过这个值应该设置成多少合适, 则是一门学问.
通常需要计算表格中有多少列,每列大致占多少宽度, nzScroll.x 的值大致是这些宽度之和.
手工计算宽度费时费力, 最好是能自动计算.
[*]另一个问题是冻结表格头, 并让表格在一定高度滚动.
通过设置 nzScroll 属性的 y 值可以做到这一点.
不过设置 nzScroll.y 也是一门学问, 因为不同屏幕大小可能需要设置不同的值,在开发阶段很难固定.
一些公司使用某些方法计算以达到自适应高度,不过大多针对比较固定的页面布局,且相对简单.
更好的办法是让用户在运行时根据自己的要求动态更新.
[*]除了表格的总宽度, 每个列的宽度设置也是一个头痛的问题.
列宽大多与内容相关, 在开发阶段设置固定列宽, 当内容超过固定宽度就会出现换行,影响美观.
如果在开发阶段设置一个默认宽度, 并在运行时可由用户修改就能解决问题.
当然最好能支持拖动表头修改列宽, 则更为方便.
[*]自定义列是很多项目的必备功能.
当表格列非常多, 用户希望只显示其中感兴趣的一部分列, 并能修改列的显示顺序.
Ng Zorro 支持自定义列功能, 不过使用起来比较复杂.
当你启用了自定义列, 用来固定左右侧的 nzLeft 和 nzRight 就变得不那么利索.
列与列之间经常会出现一些缝隙或对不齐的现象, Ng Zorro 官方文档给出了一些调整建议, 不过也是非常麻烦.
[*]诸如表格批量编辑,表格行编辑, 树形异步加载等需求都是很早之前就已经扩展支持, 就不在此一一列出.
下面介绍 Util UI 表格设置功能.
先来一个表格设置的效果图.

可以看到, 它确实解决了前面提到的棘手问题.
如何开启表格设置功能?
表格标签示例代码.
@*表格*@
<util-table id="tb" key="identity_operation" enable-table-settings="true"
    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>show-checkbox="true" show-line-number="true"
    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>url="operation" query-param="queryParam" sort="SortId">
    <i nz-icon="" nzType="setting"></i><util-td for="Name"></util-td>
    <i nz-icon="" nzType="setting"></i><util-td for="Uri"></util-td>
    <i nz-icon="" nzType="setting"></i><util-td for="IsBase" sort="false"></util-td>
    <i nz-icon="" nzType="setting"></i><util-td for="Remark"></util-td>
    <i nz-icon="" nzType="setting"></i><util-td for="Enabled">
    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i><util-tag color-type="GeekBlue" ng-if="row.enabled" text-enabled="true"></util-tag>
    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i><util-tag color-type="Red" ng-if="!row.enabled" text-not-enabled="true"></util-tag>
    <i nz-icon="" nzType="setting"></i></util-td>
    <i nz-icon="" nzType="setting"></i><util-td for="CreationTime"></util-td>
    <i nz-icon="" nzType="setting"></i><util-td for="LastModificationTime"></util-td>
    <i nz-icon="" nzType="setting"></i><util-td title-operation="true">
    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i><util-a on-click="openDetailDialog(row)" text-detail="true"></util-a>
    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i><util-container acl="operation.update">
    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i><util-divider type="Vertical"></util-divider>
    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i><util-a on-click="openEditDrawer(row)" text-update="true"></util-a>
    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i></util-container>
    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i><util-container acl="operation.delete">
    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i><util-divider type="Vertical"></util-divider>
    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i><util-a danger="true" on-click="delete(row.id)" text-delete="true"></util-a>
    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i></util-container>
    <i nz-icon="" nzType="setting"></i></util-td>
</util-table>要开启表格设置功能, 只需要在标签设置 enable-table-settings 属性为 true.
你可能要问, 需要编写 ts 脚本代码吗?
不用 !!!
如果你看过 Ng Zorro 官方自定义列的示例, 知道需要将一个 NzCustomColumn[] 对象传入 的 nzCustomColumn 属性.
那么, Util UI 的自定义列功能是否使用 Ng Zorro 官方的实现呢?
下面来看看生成的 html , 答案就会揭晓.
<nz-table #tb="" #x_tb="xTableExtend" (nzPageIndexChange)="x_tb.pageIndexChange($event)"
    <i nz-icon="" nzType="setting"></i>(nzPageSizeChange)="x_tb.pageSizeChange($event)" order="SortId" url="operation" x-table-extend=""
    <i nz-icon="" nzType="setting"></i>[(nzPageIndex)]="x_tb.queryParam.page" [(nzPageSize)]="x_tb.queryParam.pageSize" [(queryParam)]="queryParam"
    <i nz-icon="" nzType="setting"></i>="ts_tb.bordered" ="ts_tb.columns" ="x_tb.dataSource"
    <i nz-icon="" nzType="setting"></i>="false" ="x_tb.loading" ="x_tb.pageSizeOptions"
    <i nz-icon="" nzType="setting"></i>="ts_tb.scroll" ="true" ="true" ="total_tb"
    <i nz-icon="" nzType="setting"></i>="ts_tb.size" ="x_tb.total">
    <i nz-icon="" nzType="setting"></i><thead>
    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i><tr>
    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i><th (nzCheckedChange)="x_tb.masterToggle()" nzCellControl="util.checkbox"
    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>="x_tb.isMasterChecked()" ="!x_tb.dataSource.length"
    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>="x_tb.isMasterIndeterminate()" ="ts_tb.isLeft('util.checkbox')"
    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>="ts_tb.isRight('util.checkbox')" ="true"
    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>="ts_tb.getTitleAlign('util.checkbox')">
    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i></th>
    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i><th nzCellControl="util.lineNumber" ="ts_tb.isLeft('util.lineNumber')"
    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>="ts_tb.isRight('util.lineNumber')" ="ts_tb.getTitleAlign('util.lineNumber')">
    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>{{'util.lineNumber'|i18n}}
    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i></th>
    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i><th (nzResizeEnd)="ts_tb.handleResize($event,'identity.operation.name')"
    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>(nzSortOrderChange)="x_tb.sortChange('name',$event)" nz-resizable="" nzBounds="window"
    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>nzCellControl="identity.operation.name" nzPreview="" ="ts_tb.isLeft('identity.operation.name')"
    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>="ts_tb.isRight('identity.operation.name')" ="true" ="true"
    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>="ts_tb.getTitleAlign('identity.operation.name')">
    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>{{'identity.operation.name'|i18n}}
    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i><nz-resize-handle nzDirection="right"></nz-resize-handle>
    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i></th>
    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i><th (nzResizeEnd)="ts_tb.handleResize($event,'identity.operation.uri')"
    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>(nzSortOrderChange)="x_tb.sortChange('uri',$event)" nz-resizable="" nzBounds="window"
    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>nzCellControl="identity.operation.uri" nzPreview="" ="ts_tb.isLeft('identity.operation.uri')"
    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>="ts_tb.isRight('identity.operation.uri')" ="true" ="true"
    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>="ts_tb.getTitleAlign('identity.operation.uri')">
    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>{{'identity.operation.uri'|i18n}}
    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i><nz-resize-handle nzDirection="right"></nz-resize-handle>
    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i></th>
    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i><th (nzResizeEnd)="ts_tb.handleResize($event,'identity.operation.isBase')" nz-resizable="" nzBounds="window"
    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>nzCellControl="identity.operation.isBase" nzPreview=""
    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>="ts_tb.isLeft('identity.operation.isBase')"
    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>="ts_tb.isRight('identity.operation.isBase')"
    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>="ts_tb.getTitleAlign('identity.operation.isBase')">
    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>{{'identity.operation.isBase'|i18n}}
    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i><nz-resize-handle nzDirection="right"></nz-resize-handle>
    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i></th>
    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i><th (nzResizeEnd)="ts_tb.handleResize($event,'identity.operation.remark')"
    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>(nzSortOrderChange)="x_tb.sortChange('remark',$event)" nz-resizable="" nzBounds="window"
    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>nzCellControl="identity.operation.remark" nzPreview=""
    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>="ts_tb.isLeft('identity.operation.remark')"
    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>="ts_tb.isRight('identity.operation.remark')" ="true" ="true"
    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>="ts_tb.getTitleAlign('identity.operation.remark')">
    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>{{'identity.operation.remark'|i18n}}
    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i><nz-resize-handle nzDirection="right"></nz-resize-handle>
    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i></th>
    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i><th (nzResizeEnd)="ts_tb.handleResize($event,'identity.operation.enabled')"
    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>(nzSortOrderChange)="x_tb.sortChange('enabled',$event)" nz-resizable="" nzBounds="window"
    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>nzCellControl="identity.operation.enabled" nzPreview=""
    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>="ts_tb.isLeft('identity.operation.enabled')"
    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>="ts_tb.isRight('identity.operation.enabled')" ="true" ="true"
    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>="ts_tb.getTitleAlign('identity.operation.enabled')">
    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>{{'identity.operation.enabled'|i18n}}
    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i><nz-resize-handle nzDirection="right"></nz-resize-handle>
    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i></th>
    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i><th (nzResizeEnd)="ts_tb.handleResize($event,'util.creationTime')"
    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>(nzSortOrderChange)="x_tb.sortChange('creationTime',$event)" nz-resizable="" nzBounds="window"
    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>nzCellControl="util.creationTime" nzPreview="" ="ts_tb.isLeft('util.creationTime')"
    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>="ts_tb.isRight('util.creationTime')" ="true" ="true"
    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>="ts_tb.getTitleAlign('util.creationTime')">{{'util.creationTime'|i18n}}
    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i><nz-resize-handle nzDirection="right"></nz-resize-handle>
    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i></th>
    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i><th (nzResizeEnd)="ts_tb.handleResize($event,'util.lastModificationTime')"
    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>(nzSortOrderChange)="x_tb.sortChange('lastModificationTime',$event)" nz-resizable="" nzBounds="window"
    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>nzCellControl="util.lastModificationTime" nzPreview=""
    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>="ts_tb.isLeft('util.lastModificationTime')"
    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>="ts_tb.isRight('util.lastModificationTime')" ="true" ="true"
    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>="ts_tb.getTitleAlign('util.lastModificationTime')">
    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>{{'util.lastModificationTime'|i18n}}
    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i><nz-resize-handle nzDirection="right"></nz-resize-handle>
    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i></th>
    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i><th (nzResizeEnd)="ts_tb.handleResize($event,'util.operation')" nz-resizable="" nzBounds="window"
    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>nzCellControl="util.operation" nzPreview="" ="ts_tb.isLeft('util.operation')"
    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>="ts_tb.isRight('util.operation')" ="ts_tb.getTitleAlign('util.operation')">
    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>{{'util.operation'|i18n}}
    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i><nz-resize-handle nzDirection="right"></nz-resize-handle>
    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i></th>
    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i></tr>
    <i nz-icon="" nzType="setting"></i></thead>
    <i nz-icon="" nzType="setting"></i><tbody>
    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i><tr *ngFor="let row of x_tb.dataSource;index as index">
    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i><td (click)="$event.stopPropagation()" (nzCheckedChange)="x_tb.toggle(row)" nzCellControl="util.checkbox"
    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>="ts_tb.getAlign('util.checkbox')" ="x_tb.isChecked(row)"
    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>="ts_tb.isLeft('util.checkbox')" ="ts_tb.isRight('util.checkbox')"
    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>="true">
    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i></td>
    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i><td nzCellControl="util.lineNumber" ="ts_tb.getAlign('util.lineNumber')"
    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>="ts_tb.isLeft('util.lineNumber')" ="ts_tb.isRight('util.lineNumber')">
    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>{{row.lineNumber}}
    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i></td>
    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i><td nzCellControl="identity.operation.name" ="ts_tb.getAlign('identity.operation.name')"
    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>="ts_tb.getEllipsis('identity.operation.name')"
    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>="ts_tb.isLeft('identity.operation.name')" ="ts_tb.isRight('identity.operation.name')">
    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>{{row.name}}
    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i></td>
    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i><td nzCellControl="identity.operation.uri" ="ts_tb.getAlign('identity.operation.uri')"
    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>="ts_tb.getEllipsis('identity.operation.uri')"
    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>="ts_tb.isLeft('identity.operation.uri')" ="ts_tb.isRight('identity.operation.uri')">
    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>{{row.uri}}
    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i></td>
    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i><td nzCellControl="identity.operation.isBase" ="ts_tb.getAlign('identity.operation.isBase')"
    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>="ts_tb.getEllipsis('identity.operation.isBase')"
    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>="ts_tb.isLeft('identity.operation.isBase')"
    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>="ts_tb.isRight('identity.operation.isBase')">
    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i><i *ngIf="!row.isBase" nz-icon nzType="close"></i>
    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i><i *ngIf="row.isBase" nz-icon nzType="check"></i>
    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i></td>
    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i><td nzCellControl="identity.operation.remark" ="ts_tb.getAlign('identity.operation.remark')"
    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>="ts_tb.getEllipsis('identity.operation.remark')"
    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>="ts_tb.isLeft('identity.operation.remark')"
    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>="ts_tb.isRight('identity.operation.remark')">
    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>{{row.remark}}
    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i></td>
    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i><td nzCellControl="identity.operation.enabled" ="ts_tb.getAlign('identity.operation.enabled')"
    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>="ts_tb.getEllipsis('identity.operation.enabled')"
    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>="ts_tb.isLeft('identity.operation.enabled')"
    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>="ts_tb.isRight('identity.operation.enabled')">
    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i><nz-tag *ngIf="row.enabled" nzColor="geekblue">{{'util.enabled'|i18n}}</nz-tag>
    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i><nz-tag *ngIf="!row.enabled" nzColor="red">{{'util.notEnabled'|i18n}}</nz-tag>
    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i></td>
    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i><td nzCellControl="util.creationTime" ="ts_tb.getAlign('util.creationTime')"
    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>="ts_tb.getEllipsis('util.creationTime')" ="ts_tb.isLeft('util.creationTime')"
    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>="ts_tb.isRight('util.creationTime')">
    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>{{row.creationTime|date:'yyyy-MM-dd HH:mm'}}
    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i></td>
    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i><td nzCellControl="util.lastModificationTime" ="ts_tb.getAlign('util.lastModificationTime')"
    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>="ts_tb.getEllipsis('util.lastModificationTime')"
    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>="ts_tb.isLeft('util.lastModificationTime')"
    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>="ts_tb.isRight('util.lastModificationTime')">
    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>{{row.lastModificationTime|date:'yyyy-MM-dd HH:mm'}}
    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i></td>
    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i><td nzCellControl="util.operation" ="ts_tb.getAlign('util.operation')"
    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>="ts_tb.getEllipsis('util.operation')" ="ts_tb.isLeft('util.operation')"
    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>="ts_tb.isRight('util.operation')">
    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>{{'util.detail'|i18n}}
    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i><ng-container *aclIf="'operation.update'">
    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i><nz-divider nzType="vertical"></nz-divider>
    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>{{'util.update'|i18n}}
    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i></ng-container>
    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i><ng-container *aclIf="'operation.delete'">
    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i><nz-divider nzType="vertical"></nz-divider>
    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>{{'util.delete'|i18n}}
    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i></ng-container>
    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i></td>
    <i nz-icon="" nzType="setting"></i>    <i nz-icon="" nzType="setting"></i></tr>
    <i nz-icon="" nzType="setting"></i></tbody>
</nz-table>
<ng-template #total_tb="" let-range="range" let-total="">
    <i nz-icon="" nzType="setting"></i>{{ 'util.tableTotalTemplate'|i18n:{start:range,end:range,total:total} }}
</ng-template>
<x-table-settings #ts_tb=""
    <i nz-icon="" nzType="setting"></i>key="identity_operation" ="true"
    <i nz-icon="" nzType="setting"></i>="[{'title':'util.checkbox','width':x_tb.config.table.checkboxWidth,'align':'left'},
    <i nz-icon="" nzType="setting"></i>{'title':'util.lineNumber','width':x_tb.config.table.lineNumberWidth,'align':'left'},
    <i nz-icon="" nzType="setting"></i>{'title':'identity.operation.name'},{'title':'identity.operation.uri'},
    <i nz-icon="" nzType="setting"></i>{'title':'identity.operation.isBase'},{'title':'identity.operation.remark'},
    <i nz-icon="" nzType="setting"></i>{'title':'identity.operation.enabled'},{'title':'util.creationTime'},
    <i nz-icon="" nzType="setting"></i>{'title':'util.lastModificationTime'},{'title':'util.operation'}]">
</x-table-settings>观察标签, 可以发现 ="ts_tb.columns" , 说明确实使用的是 Ng Zorro 官方提供的自定义列功能.
生成的 html 比较复杂, enable-table-settings 除了开启自定义列外,还会启用拖动列宽等功能.
前面提到, Util Ui 提供的标签可以压缩 3-10 倍的 html 代码量 , 从这里可以看出, 绝非信口雌黄.
是由 util-angular 脚本库提供的表格设置组件.
的 initColumns 属性设置了一个列信息数组, 将列集合传入表格设置组件.
组件经过系列工序, 输出 Ng Zorro 需要的自定义列信息.
所以, 无需手工编写任何 ts 脚本代码, 即可完成相关功能.
可以看到,TagHelper 不仅可以封装 html 复杂度,甚至能为你生成一些简单的 js 对象.
要打开表格设置对话框, 需要一个按钮.
.cshtml 代码如下.
show-table-settings 用于显示表格设置对话框, 传入表格的引用变量名 tb.
生成的 html 如下.
    <i nz-icon="" nzType="setting"></i>Util UI 的扩展指令和组件具有一些约定的命名.
表格组件的引用变量名为 tb , 对应的表格设置组件则为 ts_tb .
表格设置组件提供了一个 show() 函数, 调用该函数即可打开表格设置窗口.

总结

本文分享了 Util 应用框架 UI 最近的突破与进展.
Util 应用框架 UI 最新架构已经稳定, 可以放心使用.
一些开发人员问到使用教程, 嗯, 这是个伤心事, Util 应用框架一直是心传口授模式, 确实没有.
不过 Util 也在考虑突破原有的使用群体, 面向更大的范围传播.
使用教程和文档已经在路上, 欢迎大家使用 , 我们将以更快的速度提供.
欢迎转载何镇汐的技术博客微信扫描二维码支持Util
来源:程序园用户自行投稿发布,如果侵权,请联系站长删除
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!
页: [1]
查看完整版本: Util 应用框架 UI 全新升级