国产 无码 综合区,色欲AV无码国产永久播放,无码天堂亚洲国产AV,国产日韩欧美女同一区二区

Util 應(yīng)用框架 UI 全新升級(jí)

這篇具有很好參考價(jià)值的文章主要介紹了Util 應(yīng)用框架 UI 全新升級(jí)。希望對(duì)大家有所幫助。如果存在錯(cuò)誤或未考慮完全的地方,請(qǐng)大家不吝賜教,您也可以點(diǎn)擊"舉報(bào)違法"按鈕提交疑問(wèn)。

Util UI 已經(jīng)開(kāi)發(fā)多年, 并在多家公司的項(xiàng)目使用.

不過(guò)一直以來(lái), Util UI 存在一些缺陷, 始終未能解決.

最近幾個(gè)月, Util 團(tuán)隊(duì)下定決心, 終于徹底解決了所有已知缺陷.

Util 應(yīng)用框架 UI 介紹

Util 應(yīng)用框架 UI 建立在 Angular , Ng-Zorro, Ng-Alain 基礎(chǔ)之上, 用于開(kāi)發(fā)企業(yè)中后臺(tái).

Util 應(yīng)用框架 UI 的特點(diǎn)

  • 簡(jiǎn)潔

    Util UI 通常可以將復(fù)雜組件的 html 代碼量壓縮 3 - 10 倍,從而使項(xiàng)目的可維護(hù)性大幅提升.

    下面以查詢(xún)表單為例進(jìn)行對(duì)比.

    先看效果演示.

    Util 應(yīng)用框架 UI 全新升級(jí)

    Util UI 的標(biāo)簽使用 TagHelper 進(jìn)行封裝 ,代碼如下.

    <util-card borderless="true" class="searchForm">
        <util-search-form label-width="120">
            <util-row gutter="24">
                <util-column>
                    <util-input id="code" name="code"  ng-model="queryParam.code" label-text="identity.application.code"/>
                </util-column>
                <util-column>
                    <util-input id="name" name="name"  ng-model="queryParam.name" label-text="identity.application.name"/>
                </util-column>
                <util-column>
                    <util-select id="enabled" name="enabled"  ng-model="queryParam.enabled" label-text="identity.application.enabled"/>
                </util-column>
                <util-column>
                    <util-input id="remark" name="remark"  ng-model="queryParam.remark" label-text="identity.application.remark"/>
                </util-column>
                <util-column>
                <util-column>
                <util-range-picker id="begin_creation_time" name="begin_creation_time"  
                    label-text="util.beginCreationTime"
                    begin-date="queryParam.beginCreationTime" end-date="queryParam.endCreationTime"/>
                </util-column>
                <util-column>
                    <util-range-picker id="begin_last_modification_time" name="begin_last_modification_time"
                        label-text="util.beginLastModificationTime"
                        begin-date="queryParam.beginLastModificationTime" end-date="queryParam.endLastModificationTime" />
                </util-column>
                <util-column class="mb-md">
                    <util-flex justify="FlexEnd" align="Center" gap="Small">
                        <util-button id="btnRefresh" icon="Sync" on-click="refresh(btnRefresh)" text-reset="true"></util-button>
                        <util-button id="btnQuery" type="Primary" icon="Search" on-click="query(btnQuery)" text-query="true"></util-button>                        
                        <util-a is-search="true" class="ml-sm"></util-a>
                    </util-flex>
                </util-column>
            </util-row>
        </util-search-form>
    </util-card>
    

    上面的標(biāo)簽會(huì)轉(zhuǎn)換成 Ng Zorro 原生的 html 標(biāo)簽.

    <nz-card class="searchForm" [nzBorderless]="true">
        <form nz-form="">
            <div nz-row="" [nzGutter]="24">
                <div nz-col="" [nzLg]="8" [nzMd]="12" [nzSm]="24" [nzXl]="8" [nzXs]="24" [nzXXl]="6">
                    <nz-form-item>
                        <nz-form-label style="width:120px">{{'identity.application.code'|i18n}}</nz-form-label>
                        <nz-form-control>
                            <nz-input-group [nzSuffix]="tmp_code">
                                <input #code="" #model_code="ngModel" name="code" nz-input="" [(ngModel)]="queryParam.code" />
                            </nz-input-group>
                            <ng-template #tmp_code="">
                                <i (click)="model_code.reset()" *ngIf="model_code.value" class="ant-input-clear-icon"
                                    nz-icon="" nzTheme="fill" nzType="close-circle">
                                </i>
                            </ng-template>
                        </nz-form-control>
                    </nz-form-item>
                </div>
                <div nz-col="" [nzLg]="8" [nzMd]="12" [nzSm]="24" [nzXl]="8" [nzXs]="24" [nzXXl]="6">
                    <nz-form-item>
                        <nz-form-label style="width:120px">{{'identity.application.name'|i18n}}</nz-form-label>
                        <nz-form-control>
                            <nz-input-group [nzSuffix]="tmp_name">
                                <input #model_name="ngModel" #name="" name="name" nz-input="" [(ngModel)]="queryParam.name" />
                            </nz-input-group>
                            <ng-template #tmp_name="">
                                <i (click)="model_name.reset()" *ngIf="model_name.value" class="ant-input-clear-icon"
                                    nz-icon="" nzTheme="fill" nzType="close-circle">
                                </i>
                            </ng-template>
                        </nz-form-control>
                    </nz-form-item>
                </div>
                <div nz-col="" [nzLg]="8" [nzMd]="12" [nzSm]="24" [nzXl]="8" [nzXs]="24" [nzXXl]="6">
                    <nz-form-item>
                        <nz-form-label style="width:120px">{{'identity.application.enabled'|i18n}}</nz-form-label>
                        <nz-form-control>
                            <nz-select #enabled="" #x_enabled="xSelectExtend" name="enabled" x-select-extend="" [(ngModel)]="queryParam.enabled">
                                <nz-option [nzLabel]="'util.defaultOptionText'|i18n"></nz-option>
                                <ng-container *ngIf="!x_enabled.isGroup">
                                    <nz-option *ngFor="let item of x_enabled.options" [nzDisabled]="item.disabled" 
                                        [nzLabel]="item.text|i18n" [nzValue]="item.value">
                                    </nz-option>
                                </ng-container>
                                <ng-container *ngIf="x_enabled.isGroup">
                                    <nz-option-group *ngFor="let group of x_enabled.optionGroups" [nzLabel]="group.text|i18n">
                                        <nz-option *ngFor="let item of group.value" [nzDisabled]="item.disabled" 
                                            [nzLabel]="item.text|i18n" [nzValue]="item.value">
                                        </nz-option>
                                    </nz-option-group>
                                </ng-container>
                            </nz-select>
                        </nz-form-control>
                    </nz-form-item>
                </div>
                <div *ngIf="expand" nz-col="" [nzLg]="8" [nzMd]="12" [nzSm]="24" [nzXl]="8" [nzXs]="24" [nzXXl]="6">
                    <nz-form-item>
                        <nz-form-label style="width:120px">{{'identity.application.remark'|i18n}}</nz-form-label>
                        <nz-form-control>
                            <nz-input-group [nzSuffix]="tmp_remark">
                                <input #model_remark="ngModel" #remark="" name="remark" nz-input="" [(ngModel)]="queryParam.remark" />
                            </nz-input-group>
                            <ng-template #tmp_remark="">
                                <i (click)="model_remark.reset()" *ngIf="model_remark.value" class="ant-input-clear-icon"
                                    nz-icon="" nzTheme="fill" nzType="close-circle">
                                </i>
                            </ng-template>
                        </nz-form-control>
                    </nz-form-item>
                </div>
                <div *ngIf="expand" nz-col="" [nzLg]="8" [nzMd]="12" [nzSm]="24" [nzXl]="8" [nzXs]="24" [nzXXl]="6">
                    <nz-form-item>
                        <nz-form-label style="width:120px">{{'util.beginCreationTime'|i18n}}</nz-form-label>
                        <nz-form-control>
                            <nz-range-picker #begin_creation_time="" #x_begin_creation_time="xRangePickerExtend" 
                                name="begin_creation_time" x-range-picker-extend="" 
                                [(beginDate)]="queryParam.beginCreationTime" [(endDate)]="queryParam.endCreationTime" 
                                [(ngModel)]="x_begin_creation_time.rangeDates">
                            </nz-range-picker>
                        </nz-form-control>
                    </nz-form-item>
                </div>
                <div *ngIf="expand" nz-col="" [nzLg]="8" [nzMd]="12" [nzSm]="24" [nzXl]="8" [nzXs]="24" [nzXXl]="6">
                    <nz-form-item>
                        <nz-form-label style="width:120px">{{'util.beginLastModificationTime'|i18n}}</nz-form-label>
                        <nz-form-control>
                            <nz-range-picker #begin_last_modification_time="" #x_begin_last_modification_time="xRangePickerExtend" 
                                name="begin_last_modification_time" x-range-picker-extend="" 
                                [(beginDate)]="queryParam.beginLastModificationTime" [(endDate)]="queryParam.endLastModificationTime" 
                                [(ngModel)]="x_begin_last_modification_time.rangeDates">
                            </nz-range-picker>
                        </nz-form-control>
                    </nz-form-item>
                </div>            
                <div class="mb-md" nz-col="" [nzLg]="{span:expand?24:24}" [nzMd]="{span:expand?24:12}" [nzSm]="24" [nzXl]="{span:expand?24:24}" 
                    [nzXs]="24" [nzXXl]="{span:expand?12:6}">
                    <div nz-flex="" nzAlign="center" nzGap="small" nzJustify="flex-end">
                        <button #btnRefresh="" (click)="refresh(btnRefresh)" nz-button="" type="button">
                            <i nz-icon="" nzType="sync"></i>
                            {{'util.reset'|i18n}}
                        </button>
                        <button #btnQuery="" (click)="query(btnQuery)" nz-button="" nzType="primary" type="button">
                            <i nz-icon="" nzType="search"></i>
                            {{'util.query'|i18n}}
                        </button>
                        <a (click)="expand=!expand" class="ml-sm">
                            {{expand?('util.collapse'|i18n):('util.expand'|i18n)}}
                            <i nz-icon="" [nzType]="expand?'up':'down'"></i>
                        </a>
                    </div>
                </div>
            </div>
        </form>
    </nz-card>
    

    <util-search-form> 是 Util UI 的查詢(xún)表單標(biāo)簽.

    查詢(xún)表單支持響應(yīng)式,并將按鈕區(qū)域始終放置在最后一行的右側(cè).

    label-width 是一個(gè)擴(kuò)展的范圍設(shè)置屬性, 為每個(gè)表單組件的 <nz-form-label> 設(shè)置 style="width:120px" 樣式, 避免了分別設(shè)置每個(gè)組件的寬度.

    Ng Zorro 表單組件由 <nz-form-item> , <nz-form-label> , <nz-form-control> 組合而成.

    <util-input> 和 <util-select> 設(shè)置了 label-text , 這是一個(gè)擴(kuò)展屬性,它會(huì)激活 <nz-form-item> 結(jié)構(gòu)的自動(dòng)創(chuàng)建.

    <util-input> 是文本框, 除了為它自動(dòng)創(chuàng)建 <nz-form-item> 結(jié)構(gòu), 還會(huì)添加清除內(nèi)容的功能.

    Util UI 大多常用組件的顯示文本會(huì)自動(dòng)添加 i18n 管道, 比如 'identity.application.code'|i18n ,用于支持多語(yǔ)言.

    從前面的示例可以看到 Util UI 可以大幅提升 html 標(biāo)簽的書(shū)寫(xiě)效率, 降低維護(hù)成本.

  • 易用

    Util 對(duì)常用功能進(jìn)行了高度封裝, 并提供簡(jiǎn)單易用的 API.

    易用性是 Util UI 封裝的關(guān)鍵目標(biāo),也是 Util UI 存在的意義.

    本文后續(xù)將以最近更新的一個(gè)關(guān)鍵功能 - 表格設(shè)置, 演示易用性.

  • 強(qiáng)類(lèi)型提示

    Util UI 提供的標(biāo)簽使用 TagHelper 技術(shù)封裝, 支持強(qiáng)類(lèi)型提示.

    如果你使用 Vs Code 開(kāi)發(fā), Util UI 標(biāo)簽提示信息大致與 Ng Zorro Vs Code 插件提示效果相當(dāng).

    Vs Code 的標(biāo)簽提示信息并不精準(zhǔn), 包含很多與 html 相關(guān)的屬性, 比如 aria- 打頭的屬性就占了幾屏, 這降低了代碼提示的作用.

    Util 應(yīng)用框架 UI 全新升級(jí)

    如果使用 Vs 開(kāi)發(fā), 甚至安裝了 Resharper , 代碼提示就能達(dá)到最佳效果.

    Util 應(yīng)用框架 UI 全新升級(jí)

  • 持續(xù)更新和改進(jìn)

    Util UI 不僅僅是對(duì) Ng Zorro 功能的簡(jiǎn)單包裝, 更提供了常用功能的擴(kuò)展.

    Util UI 擴(kuò)展功能來(lái)自之前使用其它 UI 框架的經(jīng)驗(yàn), 另外收集項(xiàng)目開(kāi)發(fā)時(shí)的實(shí)際需求,并加以整理,以滿(mǎn)足使用 Util UI 的項(xiàng)目.

    Util 團(tuán)隊(duì)傾聽(tīng)開(kāi)發(fā)人員的心聲, 并持續(xù)改進(jìn), 從而更好的滿(mǎn)足項(xiàng)目需求.

Util 應(yīng)用框架 UI 的封裝實(shí)現(xiàn)方式

  • 使用 .cshtml 替代 .html 頁(yè)面.

    .cshtml 是 .Net 提供的一種高級(jí) html 封裝技術(shù).

    Util 創(chuàng)造性的將 .cshtml 引入 Angular 應(yīng)用開(kāi)發(fā).

    Util 將 cshtml 頁(yè)面作為 html 抽象層, 用來(lái)隱藏 html 的復(fù)雜性.

    Ng Zorro 組件庫(kù)定義了大量的 Angular 組件.

    使用 Angular 組件, 就是在 html 頁(yè)面中書(shū)寫(xiě)自定義的標(biāo)簽.

    Util 應(yīng)用框架使用 TagHelper 對(duì) Ng Zorro 標(biāo)簽進(jìn)行封裝, 以提供更加簡(jiǎn)潔的用法.

    TagHelper 是一種 .Net 標(biāo)簽, 在 .cshtml 文件中使用.

    雖然 TagHelper 標(biāo)簽看上去也是一些自定義標(biāo)簽 , 但它們不是 Angular 組件.

    Util 會(huì)在開(kāi)發(fā)階段將 .cshtml 文件轉(zhuǎn)換成 html.

  • 使用 Angular 指令進(jìn)行擴(kuò)展.

    Ng Zorro 組件庫(kù)與 EasyUI 這樣的組件庫(kù)具有顯著差異.

    Ng Zorro 組件庫(kù)提供的 API 具有粒度細(xì), 擴(kuò)展性強(qiáng)的特點(diǎn).

    Ng Zorro 組件的很多功能并不內(nèi)置于組件中,而是通過(guò) Demo 的形式告訴你怎么使用.

    這為你提供了很大的靈活性和自由.

    但也意味著,如果你不加封裝,直接在項(xiàng)目中復(fù)制使用, 就會(huì)造成大量的冗余代碼, 降低項(xiàng)目的可維護(hù)性.

    要擴(kuò)展 Ng Zorro 組件, 僅使用 TagHelper 封裝 html 是不夠的, 還需要找到編寫(xiě)腳本的地方.

    封裝和擴(kuò)展 Ng Zorro 組件, 通常有兩種方式.

    • 一種方式是創(chuàng)建新的 Angular 組件對(duì)原始組件進(jìn)行包裝.

      使用組件包裝, 可以提供更加易用的 Api.

      不過(guò)這種封裝方式也有一些缺陷.

      • 新組件的 API 與原始組件可能不同, 增加了學(xué)習(xí)成本.

      • 由于需要將原始組件的 API 暴露出來(lái) , 導(dǎo)致更多的冗余代碼.

      • 擴(kuò)展性降低.

        對(duì)于表格這樣復(fù)雜的組件, html 結(jié)構(gòu)相當(dāng)復(fù)雜, 使用組件包裝通常不會(huì)保留原有的 html 結(jié)構(gòu).

        擴(kuò)展點(diǎn)完全由新組件控制, 從而降低擴(kuò)展性.

    • 另一種方式是使用 Angular 指令對(duì)原始組件進(jìn)行擴(kuò)展.

      Angular 指令使用起來(lái)就像標(biāo)簽上的屬性一樣.

      使用 Angular 指令進(jìn)行擴(kuò)展, 最大優(yōu)勢(shì)是保留原始組件的全部用法, 不會(huì)降低其擴(kuò)展性.

      當(dāng)然指令封裝方式也帶來(lái)了新的挑戰(zhàn),那就是 html 標(biāo)簽會(huì)更加復(fù)雜.

      Util UI 使用 Angular 指令進(jìn)行封裝擴(kuò)展, 并使用 TagHelper 標(biāo)簽來(lái)隱藏 html 的復(fù)雜度.

  • Lambda表達(dá)式支持

    在 .cshtml 文件中使用 TagHelper 標(biāo)簽, 你可以直接設(shè)置標(biāo)簽上的屬性.

    不過(guò) , 如果使用 .Net 開(kāi)發(fā) API 后端, 并創(chuàng)建了 DTO 對(duì)象, 你可以將 DTO 屬性直接綁定到標(biāo)簽上.

    下面演示查詢(xún)表單組件如何使用Lambda表達(dá)式綁定 DTO 屬性.

    DTO 代碼如下:

    /// <summary>
    /// 應(yīng)用程序查詢(xún)參數(shù)
    /// </summary>
    public class ApplicationQuery : QueryParameter {
        /// <summary>
        /// 應(yīng)用程序編碼
        ///</summary>
        [Description( "identity.application.code" )]
        public string Code { get; set; }
        /// <summary>
        /// 應(yīng)用程序名稱(chēng)
        ///</summary>
        [Description( "identity.application.name" )]
        public string Name { get; set; }
        /// <summary>
        /// 啟用
        ///</summary>
        [Description( "identity.application.enabled" )]
        public bool? Enabled { get; set; }
        /// <summary>
        /// 備注
        ///</summary>
        [Description( "identity.application.remark" )]
        public string Remark { get; set; }
        /// <summary>
        /// 起始創(chuàng)建時(shí)間
        /// </summary>
        [Display( Name = "util.beginCreationTime" )]
        public DateTime? BeginCreationTime { get; set; }
        /// <summary>
        /// 結(jié)束創(chuàng)建時(shí)間
        /// </summary>
        [Display( Name = "util.endCreationTime" )]
        public DateTime? EndCreationTime { get; set; }
        /// <summary>
        /// 起始最后修改時(shí)間
        /// </summary>
        [Display( Name = "util.beginLastModificationTime" )]
        public DateTime? BeginLastModificationTime { get; set; }
        /// <summary>
        /// 結(jié)束最后修改時(shí)間
        /// </summary>
        [Display( Name = "util.endLastModificationTime" )]
        public DateTime? EndLastModificationTime { get; set; }
    }
    

    .cshtml 代碼如下:

    @model ApplicationQuery
    
    <util-card borderless="true" class="searchForm">
        <util-search-form label-width="120">
            <util-row gutter="24">
                <util-column>
                    <util-input for="Code" />
                </util-column>
                <util-column>
                    <util-input for="Name" />
                </util-column>
                <util-column>
                    <util-select for="Enabled" />
                </util-column>
                <util-column>
                    <util-input for="Remark" />
                </util-column>
                <util-column>
                    <util-range-picker for-begin="BeginCreationTime" for-end="EndCreationTime" />
                </util-column>
                <util-column>
                    <util-range-picker for-begin="BeginLastModificationTime" for-end="EndLastModificationTime" />
                </util-column>
                <util-column class="mb-md" md="24">
                    <util-flex justify="FlexEnd" align="Center" gap="Small">
                        <util-button id="btnRefresh" icon="Sync" on-click="refresh(btnRefresh)" text-reset="true"></util-button>
                        <util-button id="btnQuery" type="Primary" icon="Search" on-click="query(btnQuery)" text-query="true"></util-button>
                        <util-button icon="CheckSquare" on-click="container.masterToggle()" text-select-all="true" ng-if="!container.isMasterChecked()"></util-button>
                        <util-button icon="CloseSquare" on-click="container.masterToggle()" text-deselect-all="true" ng-if="container.isMasterChecked()"></util-button>
                        <util-a is-search="true" class="ml-sm"></util-a>
                    </util-flex>
                </util-column>
            </util-row>
        </util-search-form>
    </util-card>
    

    Lambda表達(dá)式會(huì)讀取 DTO 對(duì)象的元數(shù)據(jù), 并自動(dòng)設(shè)置常用屬性, 從而再次大幅提升生產(chǎn)力.

Util 應(yīng)用框架 UI 的組成

  • Util.Ui.NgZorro

    Util.Ui.NgZorro 類(lèi)庫(kù)包含 Ng Zorro TagHelper 標(biāo)簽, 目前已封裝官方正式發(fā)布的全部組件.

  • Util.Ui.NgAlain

    Util.Ui.NgAlain 類(lèi)庫(kù)包含 Ng Alain 部分組件 TagHelper 標(biāo)簽.

  • util-angular

    util-angular 是一個(gè) typescript 腳本庫(kù), 包含 Ng Zorro 擴(kuò)展指令和常用操作 Helper.

Util 應(yīng)用框架 UI 最新進(jìn)展

Util 應(yīng)用框架 UI 最近進(jìn)行了全面改進(jìn),并取得了重大突破.

最大的進(jìn)展有2點(diǎn), 一是開(kāi)發(fā)機(jī)制的改進(jìn), 二是增加了表格設(shè)置功能.

  • 開(kāi)發(fā)機(jī)制改進(jìn)

    • 架構(gòu)缺陷

      Util 應(yīng)用框架將 .cshtml 文件引入 Angular 已有相當(dāng)長(zhǎng)的年頭.

      由于這種非主流的用法并沒(méi)有微軟官方的支持,所以一直存在相當(dāng)多的問(wèn)題.

      • 最主要的影響是導(dǎo)致開(kāi)發(fā)階段運(yùn)行緩慢.

        之前的開(kāi)發(fā)流程, Angular 組件在開(kāi)發(fā)階段直接訪(fǎng)問(wèn) cshtml 頁(yè)面,所以開(kāi)發(fā)階段必須使用 Angular JIT 模式, 它比 Angular AOT 模式要慢一些.

        cshtml 在第一次訪(fǎng)問(wèn)時(shí), 尚未創(chuàng)建緩存 , 會(huì)比較慢.

        Angular 應(yīng)用啟動(dòng)時(shí),將訪(fǎng)問(wèn)根模塊引用的所有頁(yè)面, 所以啟動(dòng)時(shí)會(huì)產(chǎn)生相當(dāng)?shù)目D.

        這個(gè)問(wèn)題通過(guò) Angular 延遲加載模塊得到緩解.

        如果項(xiàng)目比較大,包含數(shù)十個(gè)業(yè)務(wù)模塊, 將每個(gè)業(yè)務(wù)模塊創(chuàng)建為延遲加載模塊.

        當(dāng)應(yīng)用啟動(dòng)時(shí), 并不會(huì)訪(fǎng)問(wèn)所有頁(yè)面, 只有請(qǐng)求了某個(gè)業(yè)務(wù)模塊的功能, 才會(huì)訪(fǎng)問(wèn)該模塊包含的 cshtml 頁(yè)面.

        不過(guò)從 Angular 13 開(kāi)始, Angular 移除了傳統(tǒng)的視圖引擎, 導(dǎo)致上述開(kāi)發(fā)方式無(wú)法使用延遲加載模塊.

        這意味著所有業(yè)務(wù)模塊在開(kāi)發(fā)階段必須在根模塊中引用.

        Angular 應(yīng)用啟動(dòng)后將訪(fǎng)問(wèn)所有 cshtml 頁(yè)面, 這顯然是不可接受的.

        一種可行的解決辦法是使用微前端方案.

        微前端架構(gòu)將業(yè)務(wù)模塊分離到不同的項(xiàng)目從而減少應(yīng)用啟動(dòng)時(shí)間.

        一些較大的項(xiàng)目和團(tuán)隊(duì)使用微前端架構(gòu)是合適的.

        但微前端架構(gòu)具有復(fù)雜性, 使用微前端架構(gòu)代替延遲加載模塊則非常牽強(qiáng).

        這是 Util 團(tuán)隊(duì)進(jìn)行全面改造的根本原因.

      • 另一個(gè)影響是項(xiàng)目結(jié)構(gòu)比較復(fù)雜.

        Util 采用的項(xiàng)目結(jié)構(gòu)最早來(lái)自 .Net Core Angular 項(xiàng)目模板, 并加以修改.

        Angular 應(yīng)用被放在 ClientApp 目錄中.

        .cshtml 文件則被放在 Pages 目錄中.

        這導(dǎo)致組件與模板的對(duì)應(yīng)關(guān)系比較復(fù)雜.

    • 改進(jìn)方案

      很多時(shí)候, 解決問(wèn)題最重要是思路的轉(zhuǎn)變.

      之前的架構(gòu)缺陷主要來(lái)自在開(kāi)發(fā)階段讓 Angular 組件直接請(qǐng)求 cshtml 頁(yè)面,從而與原生 Angular 應(yīng)用產(chǎn)生差別.

      不過(guò), Util 使用 cshtml 僅限于開(kāi)發(fā)階段, 發(fā)布之后實(shí)際上與 cshtml 沒(méi)有任何關(guān)系.

      cshtml 的作用只是幫助生成 html 而已.

      現(xiàn)代化開(kāi)發(fā)一個(gè)重要的功能是熱更新, 比如 Angular 應(yīng)用, 它會(huì)持續(xù)監(jiān)視你的相關(guān)文件.

      當(dāng)你編輯完 .ts 或 .html 文件時(shí), 瀏覽器就會(huì)自動(dòng)刷新.

      如果我們監(jiān)視所有 .cshtml 文件,并在保存 cshtml 文件時(shí)自動(dòng)生成對(duì)應(yīng)的 html 文件,就能從根本上解決問(wèn)題.

      由于只需要處理保存的 cshtml 文件, 生成 html 的速度將非常迅速.

      當(dāng) html 生成完成, 后續(xù)流程則與原生 angular 應(yīng)用相同, 從而解決引入 cshtml 相關(guān)的所有缺陷.

      現(xiàn)在, 編輯并保存 .cshtml 文件, 瀏覽器就會(huì)自動(dòng)刷新, 與原生 Angular 應(yīng)用相比, 大致慢幾百毫秒, 通??梢院雎圆挥?jì).

      項(xiàng)目結(jié)構(gòu)復(fù)雜的問(wèn)題則很好解決, 將 .cshtml 與 Angular 組件放在一起即可.

      這與原生 Angular 應(yīng)用相似, 只需修改 .cshtml 生成 html 文件的路徑規(guī)則.

      一直以來(lái), Util UI的架構(gòu)比較臃腫, 只能在 Vs 中開(kāi)發(fā).

      但現(xiàn)在前端基本都使用 Vs Code.

      最新 UI 架構(gòu)與原生 Angular 應(yīng)用差別很小, 同樣適合使用 Vs Code 開(kāi)發(fā).

      下面是使用 Vs Code 打開(kāi)的項(xiàng)目結(jié)構(gòu).

      Util 應(yīng)用框架 UI 全新升級(jí)

  • 表格設(shè)置

    表格是業(yè)務(wù)系統(tǒng)的基石.

    我們收集了一些項(xiàng)目上使用 Ng Zorro 表格的反饋意見(jiàn).

    • 當(dāng)表格列較多時(shí),如果不進(jìn)行寬度設(shè)置, 則會(huì)顯示得很畸形.

      要解決這個(gè)問(wèn)題, 需要設(shè)置表格 nzScroll 屬性的 x 值.

      nzScroll 的 x 可以讓表格產(chǎn)生橫向的滾動(dòng)條, 從而將表格內(nèi)容拉伸.

      不過(guò)這個(gè)值應(yīng)該設(shè)置成多少合適, 則是一門(mén)學(xué)問(wèn).

      通常需要計(jì)算表格中有多少列,每列大致占多少寬度, nzScroll.x 的值大致是這些寬度之和.

      手工計(jì)算寬度費(fèi)時(shí)費(fèi)力, 最好是能自動(dòng)計(jì)算.

    • 另一個(gè)問(wèn)題是凍結(jié)表格頭, 并讓表格在一定高度滾動(dòng).

      通過(guò)設(shè)置 nzScroll 屬性的 y 值可以做到這一點(diǎn).

      不過(guò)設(shè)置 nzScroll.y 也是一門(mén)學(xué)問(wèn), 因?yàn)椴煌聊淮笮】赡苄枰O(shè)置不同的值,在開(kāi)發(fā)階段很難固定.

      一些公司使用某些方法計(jì)算以達(dá)到自適應(yīng)高度,不過(guò)大多針對(duì)比較固定的頁(yè)面布局,且相對(duì)簡(jiǎn)單.

      更好的辦法是讓用戶(hù)在運(yùn)行時(shí)根據(jù)自己的要求動(dòng)態(tài)更新.

    • 除了表格的總寬度, 每個(gè)列的寬度設(shè)置也是一個(gè)頭痛的問(wèn)題.

      列寬大多與內(nèi)容相關(guān), 在開(kāi)發(fā)階段設(shè)置固定列寬, 當(dāng)內(nèi)容超過(guò)固定寬度就會(huì)出現(xiàn)換行,影響美觀.

      如果在開(kāi)發(fā)階段設(shè)置一個(gè)默認(rèn)寬度, 并在運(yùn)行時(shí)可由用戶(hù)修改就能解決問(wèn)題.

      當(dāng)然最好能支持拖動(dòng)表頭修改列寬, 則更為方便.

    • 自定義列是很多項(xiàng)目的必備功能.

      當(dāng)表格列非常多, 用戶(hù)希望只顯示其中感興趣的一部分列, 并能修改列的顯示順序.

      Ng Zorro 支持自定義列功能, 不過(guò)使用起來(lái)比較復(fù)雜.

      當(dāng)你啟用了自定義列, 用來(lái)固定左右側(cè)的 nzLeft 和 nzRight 就變得不那么利索.

      列與列之間經(jīng)常會(huì)出現(xiàn)一些縫隙或?qū)Σ积R的現(xiàn)象, Ng Zorro 官方文檔給出了一些調(diào)整建議, 不過(guò)也是非常麻煩.

    • 諸如表格批量編輯,表格行編輯, 樹(shù)形異步加載等需求都是很早之前就已經(jīng)擴(kuò)展支持, 就不在此一一列出.

    下面介紹 Util UI 表格設(shè)置功能.

    先來(lái)一個(gè)表格設(shè)置的效果圖.

    Util 應(yīng)用框架 UI 全新升級(jí)

    可以看到, 它確實(shí)解決了前面提到的棘手問(wèn)題.

    如何開(kāi)啟表格設(shè)置功能?

    表格標(biāo)簽示例代碼.

    @*表格*@
    <util-table id="tb" key="identity_operation" enable-table-settings="true"
                show-checkbox="true" show-line-number="true" 
                url="operation" query-param="queryParam" sort="SortId">
        <util-td for="Name"></util-td>
        <util-td for="Uri"></util-td>
        <util-td for="IsBase" sort="false"></util-td>
        <util-td for="Remark"></util-td>
        <util-td for="Enabled">
            <util-tag color-type="GeekBlue" ng-if="row.enabled" text-enabled="true"></util-tag>
            <util-tag color-type="Red" ng-if="!row.enabled" text-not-enabled="true"></util-tag>
        </util-td>
        <util-td for="CreationTime"></util-td>
        <util-td for="LastModificationTime"></util-td>
        <util-td title-operation="true">
            <util-a on-click="openDetailDialog(row)" text-detail="true"></util-a>
            <util-container acl="operation.update">
                <util-divider type="Vertical"></util-divider>
                <util-a on-click="openEditDrawer(row)" text-update="true"></util-a>
            </util-container>
            <util-container acl="operation.delete">
                <util-divider type="Vertical"></util-divider>
                <util-a danger="true" on-click="delete(row.id)" text-delete="true"></util-a>
            </util-container>
        </util-td>
    </util-table>
    

    要開(kāi)啟表格設(shè)置功能, 只需要在 <util-table> 標(biāo)簽設(shè)置 enable-table-settings 屬性為 true.

    你可能要問(wèn), 需要編寫(xiě) ts 腳本代碼嗎?

    不用 !!!

    如果你看過(guò) Ng Zorro 官方自定義列的示例, 知道需要將一個(gè) NzCustomColumn[] 對(duì)象傳入 <nz-table>的 nzCustomColumn 屬性.

    那么, Util UI 的自定義列功能是否使用 Ng Zorro 官方的實(shí)現(xiàn)呢?

    下面來(lái)看看生成的 html , 答案就會(huì)揭曉.

    <nz-table #tb="" #x_tb="xTableExtend" (nzPageIndexChange)="x_tb.pageIndexChange($event)"
        (nzPageSizeChange)="x_tb.pageSizeChange($event)" order="SortId" url="operation" x-table-extend=""
        [(nzPageIndex)]="x_tb.queryParam.page" [(nzPageSize)]="x_tb.queryParam.pageSize" [(queryParam)]="queryParam"
        [nzBordered]="ts_tb.bordered" [nzCustomColumn]="ts_tb.columns" [nzData]="x_tb.dataSource"
        [nzFrontPagination]="false" [nzLoading]="x_tb.loading" [nzPageSizeOptions]="x_tb.pageSizeOptions"
        [nzScroll]="ts_tb.scroll" [nzShowQuickJumper]="true" [nzShowSizeChanger]="true" [nzShowTotal]="total_tb"
        [nzSize]="ts_tb.size" [nzTotal]="x_tb.total">
        <thead>
            <tr>
                <th (nzCheckedChange)="x_tb.masterToggle()" nzCellControl="util.checkbox"
                    [nzChecked]="x_tb.isMasterChecked()" [nzDisabled]="!x_tb.dataSource.length"
                    [nzIndeterminate]="x_tb.isMasterIndeterminate()" [nzLeft]="ts_tb.isLeft('util.checkbox')"
                    [nzRight]="ts_tb.isRight('util.checkbox')" [nzShowCheckbox]="true"
                    [titleAlign]="ts_tb.getTitleAlign('util.checkbox')">
                </th>
                <th nzCellControl="util.lineNumber" [nzLeft]="ts_tb.isLeft('util.lineNumber')"
                    [nzRight]="ts_tb.isRight('util.lineNumber')" [titleAlign]="ts_tb.getTitleAlign('util.lineNumber')">
                    {{'util.lineNumber'|i18n}}
                </th>
                <th (nzResizeEnd)="ts_tb.handleResize($event,'identity.operation.name')"
                    (nzSortOrderChange)="x_tb.sortChange('name',$event)" nz-resizable="" nzBounds="window"
                    nzCellControl="identity.operation.name" nzPreview="" [nzLeft]="ts_tb.isLeft('identity.operation.name')"
                    [nzRight]="ts_tb.isRight('identity.operation.name')" [nzShowSort]="true" [nzSortFn]="true"
                    [titleAlign]="ts_tb.getTitleAlign('identity.operation.name')">
                    {{'identity.operation.name'|i18n}}
                    <nz-resize-handle nzDirection="right"></nz-resize-handle>
                </th>
                <th (nzResizeEnd)="ts_tb.handleResize($event,'identity.operation.uri')"
                    (nzSortOrderChange)="x_tb.sortChange('uri',$event)" nz-resizable="" nzBounds="window"
                    nzCellControl="identity.operation.uri" nzPreview="" [nzLeft]="ts_tb.isLeft('identity.operation.uri')"
                    [nzRight]="ts_tb.isRight('identity.operation.uri')" [nzShowSort]="true" [nzSortFn]="true"
                    [titleAlign]="ts_tb.getTitleAlign('identity.operation.uri')">
                    {{'identity.operation.uri'|i18n}}
                    <nz-resize-handle nzDirection="right"></nz-resize-handle>
                </th>
                <th (nzResizeEnd)="ts_tb.handleResize($event,'identity.operation.isBase')" nz-resizable="" nzBounds="window"
                    nzCellControl="identity.operation.isBase" nzPreview=""
                    [nzLeft]="ts_tb.isLeft('identity.operation.isBase')"
                    [nzRight]="ts_tb.isRight('identity.operation.isBase')"
                    [titleAlign]="ts_tb.getTitleAlign('identity.operation.isBase')">
                    {{'identity.operation.isBase'|i18n}}
                    <nz-resize-handle nzDirection="right"></nz-resize-handle>
                </th>
                <th (nzResizeEnd)="ts_tb.handleResize($event,'identity.operation.remark')"
                    (nzSortOrderChange)="x_tb.sortChange('remark',$event)" nz-resizable="" nzBounds="window"
                    nzCellControl="identity.operation.remark" nzPreview=""
                    [nzLeft]="ts_tb.isLeft('identity.operation.remark')"
                    [nzRight]="ts_tb.isRight('identity.operation.remark')" [nzShowSort]="true" [nzSortFn]="true"
                    [titleAlign]="ts_tb.getTitleAlign('identity.operation.remark')">
                    {{'identity.operation.remark'|i18n}}
                    <nz-resize-handle nzDirection="right"></nz-resize-handle>
                </th>
                <th (nzResizeEnd)="ts_tb.handleResize($event,'identity.operation.enabled')"
                    (nzSortOrderChange)="x_tb.sortChange('enabled',$event)" nz-resizable="" nzBounds="window"
                    nzCellControl="identity.operation.enabled" nzPreview=""
                    [nzLeft]="ts_tb.isLeft('identity.operation.enabled')"
                    [nzRight]="ts_tb.isRight('identity.operation.enabled')" [nzShowSort]="true" [nzSortFn]="true"
                    [titleAlign]="ts_tb.getTitleAlign('identity.operation.enabled')">
                    {{'identity.operation.enabled'|i18n}}
                    <nz-resize-handle nzDirection="right"></nz-resize-handle>
                </th>
                <th (nzResizeEnd)="ts_tb.handleResize($event,'util.creationTime')"
                    (nzSortOrderChange)="x_tb.sortChange('creationTime',$event)" nz-resizable="" nzBounds="window"
                    nzCellControl="util.creationTime" nzPreview="" [nzLeft]="ts_tb.isLeft('util.creationTime')"
                    [nzRight]="ts_tb.isRight('util.creationTime')" [nzShowSort]="true" [nzSortFn]="true"
                    [titleAlign]="ts_tb.getTitleAlign('util.creationTime')">{{'util.creationTime'|i18n}}
                    <nz-resize-handle nzDirection="right"></nz-resize-handle>
                </th>
                <th (nzResizeEnd)="ts_tb.handleResize($event,'util.lastModificationTime')"
                    (nzSortOrderChange)="x_tb.sortChange('lastModificationTime',$event)" nz-resizable="" nzBounds="window"
                    nzCellControl="util.lastModificationTime" nzPreview=""
                    [nzLeft]="ts_tb.isLeft('util.lastModificationTime')"
                    [nzRight]="ts_tb.isRight('util.lastModificationTime')" [nzShowSort]="true" [nzSortFn]="true"
                    [titleAlign]="ts_tb.getTitleAlign('util.lastModificationTime')">
                    {{'util.lastModificationTime'|i18n}}
                    <nz-resize-handle nzDirection="right"></nz-resize-handle>
                </th>
                <th (nzResizeEnd)="ts_tb.handleResize($event,'util.operation')" nz-resizable="" nzBounds="window"
                    nzCellControl="util.operation" nzPreview="" [nzLeft]="ts_tb.isLeft('util.operation')"
                    [nzRight]="ts_tb.isRight('util.operation')" [titleAlign]="ts_tb.getTitleAlign('util.operation')">
                    {{'util.operation'|i18n}}
                    <nz-resize-handle nzDirection="right"></nz-resize-handle>
                </th>
            </tr>
        </thead>
        <tbody>
            <tr *ngFor="let row of x_tb.dataSource;index as index">
                <td (click)="$event.stopPropagation()" (nzCheckedChange)="x_tb.toggle(row)" nzCellControl="util.checkbox"
                    [nzAlign]="ts_tb.getAlign('util.checkbox')" [nzChecked]="x_tb.isChecked(row)"
                    [nzLeft]="ts_tb.isLeft('util.checkbox')" [nzRight]="ts_tb.isRight('util.checkbox')"
                    [nzShowCheckbox]="true">
                </td>
                <td nzCellControl="util.lineNumber" [nzAlign]="ts_tb.getAlign('util.lineNumber')"
                    [nzLeft]="ts_tb.isLeft('util.lineNumber')" [nzRight]="ts_tb.isRight('util.lineNumber')">
                    {{row.lineNumber}}
                </td>
                <td nzCellControl="identity.operation.name" [nzAlign]="ts_tb.getAlign('identity.operation.name')"
                    [nzEllipsis]="ts_tb.getEllipsis('identity.operation.name')"
                    [nzLeft]="ts_tb.isLeft('identity.operation.name')" [nzRight]="ts_tb.isRight('identity.operation.name')">
                    {{row.name}}
                </td>
                <td nzCellControl="identity.operation.uri" [nzAlign]="ts_tb.getAlign('identity.operation.uri')"
                    [nzEllipsis]="ts_tb.getEllipsis('identity.operation.uri')"
                    [nzLeft]="ts_tb.isLeft('identity.operation.uri')" [nzRight]="ts_tb.isRight('identity.operation.uri')">
                    {{row.uri}}
                </td>
                <td nzCellControl="identity.operation.isBase" [nzAlign]="ts_tb.getAlign('identity.operation.isBase')"
                    [nzEllipsis]="ts_tb.getEllipsis('identity.operation.isBase')"
                    [nzLeft]="ts_tb.isLeft('identity.operation.isBase')"
                    [nzRight]="ts_tb.isRight('identity.operation.isBase')">
                    <i *ngIf="!row.isBase" nz-icon nzType="close"></i>
                    <i *ngIf="row.isBase" nz-icon nzType="check"></i>
                </td>
                <td nzCellControl="identity.operation.remark" [nzAlign]="ts_tb.getAlign('identity.operation.remark')"
                    [nzEllipsis]="ts_tb.getEllipsis('identity.operation.remark')"
                    [nzLeft]="ts_tb.isLeft('identity.operation.remark')"
                    [nzRight]="ts_tb.isRight('identity.operation.remark')">
                    {{row.remark}}
                </td>
                <td nzCellControl="identity.operation.enabled" [nzAlign]="ts_tb.getAlign('identity.operation.enabled')"
                    [nzEllipsis]="ts_tb.getEllipsis('identity.operation.enabled')"
                    [nzLeft]="ts_tb.isLeft('identity.operation.enabled')"
                    [nzRight]="ts_tb.isRight('identity.operation.enabled')">
                    <nz-tag *ngIf="row.enabled" nzColor="geekblue">{{'util.enabled'|i18n}}</nz-tag>
                    <nz-tag *ngIf="!row.enabled" nzColor="red">{{'util.notEnabled'|i18n}}</nz-tag>
                </td>
                <td nzCellControl="util.creationTime" [nzAlign]="ts_tb.getAlign('util.creationTime')"
                    [nzEllipsis]="ts_tb.getEllipsis('util.creationTime')" [nzLeft]="ts_tb.isLeft('util.creationTime')"
                    [nzRight]="ts_tb.isRight('util.creationTime')">
                    {{row.creationTime|date:'yyyy-MM-dd HH:mm'}}
                </td>
                <td nzCellControl="util.lastModificationTime" [nzAlign]="ts_tb.getAlign('util.lastModificationTime')"
                    [nzEllipsis]="ts_tb.getEllipsis('util.lastModificationTime')"
                    [nzLeft]="ts_tb.isLeft('util.lastModificationTime')"
                    [nzRight]="ts_tb.isRight('util.lastModificationTime')">
                    {{row.lastModificationTime|date:'yyyy-MM-dd HH:mm'}}
                </td>
                <td nzCellControl="util.operation" [nzAlign]="ts_tb.getAlign('util.operation')"
                    [nzEllipsis]="ts_tb.getEllipsis('util.operation')" [nzLeft]="ts_tb.isLeft('util.operation')"
                    [nzRight]="ts_tb.isRight('util.operation')">
                    <a (click)="openDetailDialog(row)">{{'util.detail'|i18n}}</a>
                    <ng-container *aclIf="'operation.update'">
                        <nz-divider nzType="vertical"></nz-divider>
                        <a (click)="openEditDrawer(row)">{{'util.update'|i18n}}</a>
                    </ng-container>
                    <ng-container *aclIf="'operation.delete'">
                        <nz-divider nzType="vertical"></nz-divider>
                        <a (click)="delete(row.id)" class="ant-btn-dangerous">{{'util.delete'|i18n}}</a>
                    </ng-container>
                </td>
            </tr>
        </tbody>
    </nz-table>
    <ng-template #total_tb="" let-range="range" let-total="">
        {{ 'util.tableTotalTemplate'|i18n:{start:range[0],end:range[1],total:total} }}
    </ng-template>
    <x-table-settings #ts_tb=""
        key="identity_operation" [enableFixedColumn]="true"
        [initColumns]="[{'title':'util.checkbox','width':x_tb.config.table.checkboxWidth,'align':'left'},
        {'title':'util.lineNumber','width':x_tb.config.table.lineNumberWidth,'align':'left'},
        {'title':'identity.operation.name'},{'title':'identity.operation.uri'},
        {'title':'identity.operation.isBase'},{'title':'identity.operation.remark'},
        {'title':'identity.operation.enabled'},{'title':'util.creationTime'},
        {'title':'util.lastModificationTime'},{'title':'util.operation'}]">
    </x-table-settings>
    

    觀察 <nz-table> 標(biāo)簽, 可以發(fā)現(xiàn) [nzCustomColumn]="ts_tb.columns" , 說(shuō)明確實(shí)使用的是 Ng Zorro 官方提供的自定義列功能.

    生成的 html 比較復(fù)雜, enable-table-settings 除了開(kāi)啟自定義列外,還會(huì)啟用拖動(dòng)列寬等功能.

    前面提到, Util Ui 提供的標(biāo)簽可以壓縮 3-10 倍的 html 代碼量 , 從這里可以看出, 絕非信口雌黃.

    <x-table-settings> 是由 util-angular 腳本庫(kù)提供的表格設(shè)置組件.

    <x-table-settings> 的 initColumns 屬性設(shè)置了一個(gè)列信息數(shù)組, 將列集合傳入表格設(shè)置組件.

    <x-table-settings> 組件經(jīng)過(guò)系列工序, 輸出 Ng Zorro 需要的自定義列信息.

    所以, 無(wú)需手工編寫(xiě)任何 ts 腳本代碼, 即可完成相關(guān)功能.

    可以看到, TagHelper 不僅可以封裝 html 復(fù)雜度,甚至能為你生成一些簡(jiǎn)單的 js 對(duì)象.

    要打開(kāi)表格設(shè)置對(duì)話(huà)框, 需要一個(gè)按鈕.

    .cshtml 代碼如下.

    show-table-settings 用于顯示表格設(shè)置對(duì)話(huà)框, 傳入表格的引用變量名 tb.

    <util-a show-table-settings="tb"></util-a>
    

    生成的 html 如下.

    <a (click)="ts_tb.show()" nz-tooltip="" [nzTooltipTitle]="'util.tableSettings'|i18n">
        <i nz-icon="" nzType="setting"></i>
    </a>
    

    Util UI 的擴(kuò)展指令和組件具有一些約定的命名.

    表格組件的引用變量名為 tb , 對(duì)應(yīng)的表格設(shè)置組件則為 ts_tb .

    表格設(shè)置組件提供了一個(gè) show() 函數(shù), 調(diào)用該函數(shù)即可打開(kāi)表格設(shè)置窗口.

總結(jié)

本文分享了 Util 應(yīng)用框架 UI 最近的突破與進(jìn)展.

Util 應(yīng)用框架 UI 最新架構(gòu)已經(jīng)穩(wěn)定, 可以放心使用.

一些開(kāi)發(fā)人員問(wèn)到使用教程, 嗯, 這是個(gè)傷心事, Util 應(yīng)用框架一直是心傳口授模式, 確實(shí)沒(méi)有.

不過(guò) Util 也在考慮突破原有的使用群體, 面向更大的范圍傳播.

使用教程和文檔已經(jīng)在路上, 歡迎大家使用 , 我們將以更快的速度提供.文章來(lái)源地址http://www.zghlxwxcb.cn/news/detail-860932.html

到了這里,關(guān)于Util 應(yīng)用框架 UI 全新升級(jí)的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!

本文來(lái)自互聯(lián)網(wǎng)用戶(hù)投稿,該文觀點(diǎn)僅代表作者本人,不代表本站立場(chǎng)。本站僅提供信息存儲(chǔ)空間服務(wù),不擁有所有權(quán),不承擔(dān)相關(guān)法律責(zé)任。如若轉(zhuǎn)載,請(qǐng)注明出處: 如若內(nèi)容造成侵權(quán)/違法違規(guī)/事實(shí)不符,請(qǐng)點(diǎn)擊違法舉報(bào)進(jìn)行投訴反饋,一經(jīng)查實(shí),立即刪除!

領(lǐng)支付寶紅包贊助服務(wù)器費(fèi)用

相關(guān)文章

  • Util應(yīng)用框架 7.x 來(lái)了

    Util是一個(gè).Net平臺(tái)下的應(yīng)用框架,旨在提升中小團(tuán)隊(duì)的開(kāi)發(fā)能力,由工具類(lèi)、分層架構(gòu)基類(lèi)、Ui組件,配套代碼生成模板,權(quán)限等組成。 Util應(yīng)用框架的最新版本是7.x,保持與.Net最新穩(wěn)定版本同步更新。 與Util 1.x相比,最新版本代碼經(jīng)過(guò)完全重寫(xiě),提升了模塊化程度,拋棄了一些歷

    2024年02月08日
    瀏覽(15)
  • Util應(yīng)用框架基礎(chǔ)(六) - 日志記錄(一) - 正文

    本文介紹Util應(yīng)用框架如何記錄日志. 日志記錄共分4篇,本文是正文,后續(xù)還有3篇分別介紹寫(xiě)入不同日志接收器的安裝和配置方法. 日志記錄對(duì)于了解系統(tǒng)執(zhí)行情況非常重要. Asp.Net Core 抽象了日志基礎(chǔ)架構(gòu),支持使用日志提供程序進(jìn)行擴(kuò)展,提供控制臺(tái)日志等簡(jiǎn)單實(shí)現(xiàn). Serilog 是 .N

    2024年02月05日
    瀏覽(19)
  • Util應(yīng)用框架基礎(chǔ)(三) - 面向切面編程(AspectCore AOP)

    本節(jié)介紹Util應(yīng)用框架對(duì)AspectCore AOP的使用. 有些問(wèn)題需要在系統(tǒng)中全局處理,比如記錄異常錯(cuò)誤日志. 如果在每個(gè)出現(xiàn)問(wèn)題的地方進(jìn)行處理,不僅費(fèi)力,還可能產(chǎn)生大量冗余代碼,并打斷業(yè)務(wù)邏輯的編寫(xiě). 這類(lèi)跨多個(gè)業(yè)務(wù)模塊的非功能需求,被稱(chēng)為 橫切關(guān)注點(diǎn) . 我們需要把橫切關(guān)注點(diǎn)

    2024年02月05日
    瀏覽(72)
  • Android全新UI框架之Jetpack Compose入門(mén)基礎(chǔ)

    Android全新UI框架之Jetpack Compose入門(mén)基礎(chǔ)

    Jetpack Compose是什么 如果有跨端開(kāi)發(fā)經(jīng)驗(yàn)的同學(xué),理解和學(xué)習(xí)compose可能沒(méi)有那么大的壓力。簡(jiǎn)單地說(shuō),compose可以讓Android的原生開(kāi)發(fā)也可以使用類(lèi)似rn的jsx的語(yǔ)法來(lái)開(kāi)發(fā) UI界面 。以往,我們開(kāi)發(fā)Android原生頁(yè)面的時(shí)候,通常是在xml中畫(huà)相關(guān)的UI控件,然后在activity中通過(guò)findViewB

    2024年02月21日
    瀏覽(24)
  • android 五大應(yīng)用開(kāi)發(fā)框架(1),騰訊竟然又偷偷開(kāi)源了一套Android原生UI框架

    android 五大應(yīng)用開(kāi)發(fā)框架(1),騰訊竟然又偷偷開(kāi)源了一套Android原生UI框架

    2、Android Runtime Android包含一個(gè)核心庫(kù)的集合,提供大部分在Java編程語(yǔ)言核心類(lèi)庫(kù)中可用的功能。每一個(gè)Android應(yīng)用程序是Dalvik虛擬機(jī)中的實(shí)例,運(yùn)行在他們自己的進(jìn)程中。Dalvik虛擬機(jī)設(shè)計(jì)成,在一個(gè)設(shè)備可以高效地運(yùn)行多個(gè)虛擬機(jī)。Dalvik虛擬機(jī)可執(zhí)行文件格式是.dex,dex格式是

    2024年04月09日
    瀏覽(97)
  • 基于Thinkphp6框架全新UI的AI網(wǎng)址導(dǎo)航系統(tǒng)源碼

    基于Thinkphp6框架全新UI的AI網(wǎng)址導(dǎo)航系統(tǒng)源碼

    2023全新UI的AI網(wǎng)址導(dǎo)航系統(tǒng)源碼,基于thinkphp6框架開(kāi)發(fā)的 AI?網(wǎng)址導(dǎo)航是一個(gè)非常實(shí)用的工具,它能夠幫助用戶(hù)方便地瀏覽和管理自己喜歡的網(wǎng)站。 相比于其他的 AI 網(wǎng)址導(dǎo)航,這個(gè)項(xiàng)目使用了更加友好和易用的 ThinkPHP 框架進(jìn)行搭建,使得開(kāi)發(fā)者和用戶(hù)都能夠輕松上手。 此次

    2024年02月11日
    瀏覽(25)
  • 界面開(kāi)發(fā)框架DevExpress XAF v24.1新版預(yù)告 - 跨平臺(tái)應(yīng)用UI(一)

    界面開(kāi)發(fā)框架DevExpress XAF v24.1新版預(yù)告 - 跨平臺(tái)應(yīng)用UI(一)

    DevExpress XAF是一款強(qiáng)大的現(xiàn)代應(yīng)用程序框架,允許同時(shí)開(kāi)發(fā)ASP.NET和WinForms。XAF采用模塊化設(shè)計(jì),開(kāi)發(fā)人員可以選擇內(nèi)建模塊,也可以自行創(chuàng)建,從而以更快的速度和比開(kāi)發(fā)人員當(dāng)前更強(qiáng)有力的方式創(chuàng)建應(yīng)用程序。 本文中的內(nèi)容概述了XAF跨平臺(tái).NET應(yīng)用UI和DevExpress .NET App、Web A

    2024年04月13日
    瀏覽(89)
  • 界面開(kāi)發(fā)框架DevExpress XAF v24.1新版預(yù)告 - 跨平臺(tái)應(yīng)用UI(二)

    界面開(kāi)發(fā)框架DevExpress XAF v24.1新版預(yù)告 - 跨平臺(tái)應(yīng)用UI(二)

    DevExpress XAF是一款強(qiáng)大的現(xiàn)代應(yīng)用程序框架,允許同時(shí)開(kāi)發(fā)ASP.NET和WinForms。XAF采用模塊化設(shè)計(jì),開(kāi)發(fā)人員可以選擇內(nèi)建模塊,也可以自行創(chuàng)建,從而以更快的速度和比開(kāi)發(fā)人員當(dāng)前更強(qiáng)有力的方式創(chuàng)建應(yīng)用程序。 本文中的內(nèi)容概述了XAF跨平臺(tái).NET應(yīng)用UI和DevExpress .NET App、Web A

    2024年04月23日
    瀏覽(99)
  • Tokenview再度升級(jí):全新Web3開(kāi)發(fā)者APIs數(shù)據(jù)服務(wù)體驗(yàn)!

    Tokenview再度升級(jí):全新Web3開(kāi)發(fā)者APIs數(shù)據(jù)服務(wù)體驗(yàn)!

    Tokenview發(fā)布全新版本的區(qū)塊鏈APIs和數(shù)據(jù)服務(wù)平臺(tái),為開(kāi)發(fā)者打造更強(qiáng)大、更便捷的開(kāi)發(fā)體驗(yàn)! 此次升級(jí),我們整合了開(kāi)發(fā)者使用習(xí)慣以及Tokenview產(chǎn)品優(yōu)勢(shì)。我們深知對(duì)于開(kāi)發(fā)者來(lái)說(shuō),時(shí)間是非常寶貴的,因此我們努力提供一個(gè)高效的頁(yè)面結(jié)構(gòu),幫助您更快速地找到所需的信

    2024年02月11日
    瀏覽(29)
  • STM32物聯(lián)網(wǎng)實(shí)戰(zhàn)開(kāi)發(fā)(1)——全新的程序框架

    STM32物聯(lián)網(wǎng)實(shí)戰(zhàn)開(kāi)發(fā)(1)——全新的程序框架

    ????????現(xiàn)在STM32公司主推的是HAL庫(kù)的開(kāi)發(fā),標(biāo)準(zhǔn)庫(kù)已經(jīng)不再更新。通過(guò)STM32cubeMX的圖形界面生成代碼非常的方便。 1、STM32cubeMX 生成的代碼與添加的應(yīng)用代碼分離; 2、利用 STM32cubeMX 重新生成代碼,不影響應(yīng)用代碼; 3、應(yīng)用代碼的添加,移除與修改,不影響 cube 生成的代

    2024年02月01日
    瀏覽(16)

覺(jué)得文章有用就打賞一下文章作者

支付寶掃一掃打賞

博客贊助

微信掃一掃打賞

請(qǐng)作者喝杯咖啡吧~博客贊助

支付寶掃一掃領(lǐng)取紅包,優(yōu)惠每天領(lǐng)

二維碼1

領(lǐng)取紅包

二維碼2

領(lǐng)紅包