成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專欄INFORMATION COLUMN

前端數(shù)據(jù)模型Model;適用于多人團(tuán)隊(duì)協(xié)作的開發(fā)模式

linkFly / 2026人閱讀

摘要:前言本文講述的數(shù)據(jù)模型并不是一個(gè)庫,也不是需要的包,僅僅只是一種在多人團(tuán)隊(duì)協(xié)作開發(fā)的時(shí)候擬定的規(guī)則。至少目前為止,我們的開發(fā)團(tuán)隊(duì)再也沒用過雖然一開始也沒用,也不用擔(dān)心后臺(tái)數(shù)據(jù)的字段或結(jié)構(gòu)發(fā)生變動(dòng),真正實(shí)現(xiàn)前后臺(tái)并行開發(fā)的愉快模式。

前言

本文講述的數(shù)據(jù)模型并不是一個(gè)庫,也不是需要npm的包,僅僅只是一種在多人團(tuán)隊(duì)協(xié)作開發(fā)的時(shí)候擬定的規(guī)則。至少目前為止,我們的開發(fā)團(tuán)隊(duì)再也沒用過mock(雖然一開始也沒用),也不用擔(dān)心后臺(tái)數(shù)據(jù)的字段或結(jié)構(gòu)發(fā)生變動(dòng),真正實(shí)現(xiàn)前后臺(tái)并行開發(fā)的愉快模式。

本文技術(shù)棧有 Typescript、Rxjs、AngularX
定義Model

類比于java里的類,我們的Model也是一個(gè)類,是TS的類,我們根據(jù)需求和設(shè)計(jì)圖或原型圖規(guī)劃好某一個(gè)具體的模塊的基類Model,并自行定義一些字段和枚舉類型,方法屬性等,并不需要強(qiáng)行和后臺(tái)的字段一致,要保證百分百純的前后端分離,舉個(gè)例子

比如開發(fā)某一個(gè)后臺(tái)管理項(xiàng)目,里邊有產(chǎn)品(Product)模塊、用戶(User)模塊等

那么我們會(huì)在model文件夾里定義BaseProduct的基類

export class BaseProductModel {
    constructor() {}
    // 必有id 和 name
    public id: number = null;
    public name: string = "";
    /...more.../
}

基類的定義是必要的,可以節(jié)省很多不必要的代碼,并不需要寫一個(gè)頁面或組件就重新定義新的model,如果某一個(gè)組件里面需要對(duì)這個(gè)產(chǎn)品的內(nèi)容進(jìn)行拓展的大可直接繼承,并不會(huì)影響其他有了這個(gè)基類的文件

我們推崇一切基類都必須繼承,不可直接構(gòu)造

真實(shí)的項(xiàng)目中產(chǎn)品的字段和屬性肯定不止只有id和name,可能還包含版本、縮略圖地址、唯一標(biāo)識(shí)、產(chǎn)品、對(duì)應(yīng)規(guī)格的價(jià)格、狀態(tài)、創(chuàng)建時(shí)間等等;這些屬性完全可以放在基類里,因?yàn)樗挟a(chǎn)品都有這些屬性,說到類型和狀態(tài)的定義,請(qǐng)注意

絕對(duì)不能將可枚舉性質(zhì)的屬性直接使用后臺(tái)或第三方返回的對(duì)應(yīng)屬性

比如,產(chǎn)品模塊里最基礎(chǔ)的狀態(tài)(status)屬性,假設(shè)后臺(tái)定義的對(duì)應(yīng)狀態(tài)有

0: 禁用
1: 啟用
2: 隱藏
3: 不可購(gòu)買

這四種,倘若我們?cè)陧?xiàng)目當(dāng)中直接使用這些對(duì)應(yīng)狀態(tài)的數(shù)字去判斷或進(jìn)行邏輯處理,分不分的清另談,如果中途或以后狀態(tài)的數(shù)字變了,GG??赡艽蠹矣X得這樣的情況很少,但也不是沒有,一旦出現(xiàn)改起來BUG就一堆。

所以對(duì)于這種可枚舉性質(zhì)的屬性我們會(huì)定義一個(gè)枚舉類(Enum)

export enum EStatus {
    BAN = 0,
    OPEN = 1,
    HIDE = 2,
    NOTBUY = 3
}

然后在model里這樣

export class BaseProductModel {
    // ......
    public status: string = EStatus[1] // 默認(rèn)啟用
}

美滋滋,而且在進(jìn)行邏輯判斷的時(shí)候我們也不用去關(guān)心每個(gè)狀態(tài)對(duì)應(yīng)的數(shù)字是什么,我們只關(guān)心它是BAN還是OPEN,簡(jiǎn)潔明了不含糊

而且我們還可以給model增加一個(gè)只讀屬性,用來返回這個(gè)狀態(tài)對(duì)應(yīng)的中文提示(這種需求很常見)

public get conversionStatusHint() : string {
    const _ = { BAN: "禁用", OPEN: "啟用", HIDE: "隱藏", NOTBUY: "買不得呀" }
    return _[this.status] ? _[this.status] : ""
}

這樣就不用在每一個(gè)組件里面寫一個(gè)方法來傳參數(shù)返回中文名稱了

到了這里,我們的BaseProductModel已經(jīng)算是定義好了,下面我們就需要給這個(gè)model定義一個(gè)方法

目的是把后臺(tái)返回的字段和數(shù)據(jù)結(jié)構(gòu)轉(zhuǎn)化為我們自己定義的字段和數(shù)據(jù)結(jié)構(gòu)
轉(zhuǎn)化后臺(tái)數(shù)據(jù)

可能到了這里很多人會(huì)覺得這是多此一舉,后臺(tái)都直接返回?cái)?shù)據(jù)了還轉(zhuǎn)化什么,返回什么用什么就得了。
但在大型的團(tuán)隊(duì)開發(fā)項(xiàng)目當(dāng)中,誰也不能保證一個(gè)字段也不修改,一個(gè)字段也不刪除或增加或缺失,牽一發(fā)動(dòng)全身。人生苦短。而且還有一種情況就是,可能這個(gè)項(xiàng)目是前端先進(jìn)行,后臺(tái)還未介入,需要前端這邊先把整體的功能和樣式都先根據(jù)設(shè)計(jì)圖規(guī)劃開發(fā)。

export class BaseProductModel {
    // ......
    // 轉(zhuǎn)化后臺(tái)數(shù)據(jù)
    public setData( data: BaseProductModel ): void {
        if (data) {
            for (let e in this) {
                if ((data).hasOwnProperty(e)) {
                    if( e == "status" ) {
                        this.status = EStatus[(data)[e]]
                    } else {
                        this[e] = (data)[e];
                    }
                }
            }
        }
    }
}

然后在調(diào)用的時(shí)候

/** 假設(shè)ProductModel類繼承了BaseProductModel類 */
public productModel: ProductModel = new ProductModel();
/...more.../
this.productModel.setData({
    // 假設(shè)后臺(tái)定義的創(chuàng)建時(shí)間字段是create_at,model里定的創(chuàng)建時(shí)間是createTime
    createTime: data.create_at
});
// 即使數(shù)據(jù)結(jié)構(gòu)不一致也可在這里進(jìn)行統(tǒng)一轉(zhuǎn)化

做好了轉(zhuǎn)化這一步,所有的數(shù)據(jù)變動(dòng)和數(shù)據(jù)結(jié)構(gòu)的變化都在這同一個(gè)地方修改即搞定,這個(gè)時(shí)候隨便后臺(tái)怎么改,歡樂改,都不影響我們后續(xù)的邏輯處理和字段的變動(dòng)。同理,在post數(shù)據(jù)給后臺(tái)的時(shí)候轉(zhuǎn)化就顯得容易多了,后臺(tái)需要什么數(shù)據(jù)和字段再轉(zhuǎn)化一次不就得了。

以上的數(shù)據(jù)模型可以很好的降低前后臺(tái)掐架的概率,mock?不需要

下面是一個(gè)我們抽離出來的常用的表格數(shù)據(jù)模型基類

import { BehaviorSubject } from "rxjs"

//分頁配置
export interface PaginationConfig {
    // 當(dāng)前的頁碼
    pageIndex: number;
    // 總數(shù)
    total: number;
    // 當(dāng)前選中的一頁顯示多少個(gè)的數(shù)量
    rows: number;
    // 可選擇的每頁顯示多少個(gè)數(shù)量
    rowsOptions?: Array;
}

//分頁配置初始數(shù)據(jù)
export let PaginationInitConfig: PaginationConfig = {
    pageIndex: 1,
    total: 0,
    rows: 10,
    rowsOptions: [10, 20, 50]
}

//表格配置
export interface TableConfig extends PaginationConfig {
    // 是否顯示loading效果
    isLoading?: boolean;
    // 是否處于半選狀態(tài)
    isCheckIndeterminate?: boolean;
    // 是否全選狀態(tài)
    isCheckAll?: boolean;
    // 是否禁用選中
    isCheckDisable?: boolean;
    //沒有數(shù)據(jù)的提示
    noResult?: string;

}

//表頭
export interface TableHead {
    titles: string[];
    widths?: string[];
    //樣式類  src/styles/ 中有公用的表格樣式類
    classes?: string[];
    sorts?: (boolean | string)[];
}

//分頁參數(shù)
export interface PageParam {
    page: number;
    rows: number;
}

//排序類型
export type orderType = "desc" | "asc" | null | ""

//排序參數(shù)
export interface SortParam {
    orderBy?: string;
    order?: orderType
}

// 所有表格的基類
export class BaseTableModel {
    //表格配置
    tableConfig: TableConfig
    //表格頭部配置
    tableHead: TableHead
    //表格數(shù)據(jù)流
    tableData$: BehaviorSubject

    //排序類型
    orderType: orderType
    //當(dāng)前排序的標(biāo)示
    currentSortBy: string

    constructor(
        //選中的 key
        private checkKey: string = "isChecked",
        //禁用的 key
        private disabledKey: string = "isDisabled"
    ) {
        this.initData()
    }

    // 重置數(shù)據(jù)
    public initData(): void {
        this.tableHead = {
            titles: []
        }
        this.tableConfig = {
            pageIndex: 1,
            total: 0,
            rows: 10,
            rowsOptions: [10, 20, 50],
            isLoading: false,
            isCheckIndeterminate: false,
            isCheckAll: false,
            isCheckDisable: false,
            noResult: "暫無數(shù)據(jù)"
        }
        this.tableData$ = new BehaviorSubject([])
    }

    /**
     * 設(shè)置表格配置
     * @author GR-05
     * @param conf
     */
    setConfig(conf: TableConfig): void {
        this.tableConfig = Object.assign(this.tableConfig, conf)
    }

    /**
     * 設(shè)置表格頭部標(biāo)題
     * @author GR-05
     * @param titles
     */
    setHeadTitles(titles: string[]): void {
        this.tableHead.titles = titles
    }

    /**
     * 設(shè)置表格頭部寬度
     * @author GR-05
     * @param widths
     */
    setHeadWidths(widths: string[]): void {
        this.tableHead.widths = widths
    }

    /**
     * 設(shè)置表格頭部樣式類
     * @author GR-05
     * @param classes
     */
    setHeadClasses(classes: string[]): void {
        this.tableHead.classes = classes
    }

    /**
     * 設(shè)置表格排序功能
     * @author GR-05
     * @param sorts
     */
    setHeadSorts(sorts: (boolean | string)[]): void {
        this.tableHead.sorts = sorts
    }

    /**
     * 設(shè)置當(dāng)前排序類型
     * @param ot
     */
    setSortType(ot: orderType) {
        this.orderType = ot
    }

    /**
     * 設(shè)置當(dāng)前排序標(biāo)識(shí)
     * @param orderBy
     */
    setSortBy(orderBy: string) {
        this.currentSortBy = orderBy
    }

    /**
     * 設(shè)置當(dāng)前被點(diǎn)擊的排序標(biāo)示
     * @param i 排序數(shù)組索引
     */
    sortByClick(i: number) {
        if (this.tableHead.sorts && this.tableHead.sorts[i]) {
            if (!this.orderType) {
                this.orderType = "desc"
            } else {
                this.orderType == "desc" ? this.orderType = "asc" : this.orderType = "desc"
            }
            this.currentSortBy = this.tableHead.sorts[i] as string
        }
    }

    /**
     * 獲取當(dāng)前的排序參數(shù)
     */
    getCurrentSort(): SortParam {
        return {
            order: this.orderType,
            orderBy: this.currentSortBy
        }
    }

    /**
     * 設(shè)置表格loading
     * @author GR-05
     * @param flag
     */
    setLoading(flag: boolean = true): void {
        this.tableConfig.isLoading = flag
    }

    /**
     * 設(shè)置當(dāng)前表格數(shù)據(jù)總數(shù)
     * @author GR-05
     * @param total
     */
    setTotal(total: number): void {
        this.tableConfig.total = total
    }

    setPageAndRows(pageIndex: number, rows: number = 10) {
        this.tableConfig.pageIndex = pageIndex
        this.tableConfig.rows = rows
    }

    /**
     * 更新表格數(shù)據(jù)(新數(shù)據(jù)、單選、多選)
     * @author GR-05
     * @param dataList
     */
    setDataList(dataList: T[]): void {
        this.tableConfig.isCheckAll = false
        this.tableConfig.isCheckIndeterminate = dataList.filter(item => !item[this.disabledKey]).some(item => item[this.checkKey] == true)
        this.tableConfig.isCheckAll = dataList.filter(item => !item[this.disabledKey]).every(item => item[this.checkKey] == true)
        this.tableConfig.isCheckAll ? this.tableConfig.isCheckIndeterminate = false : {}
        this.tableData$.next(dataList);
        if (dataList.length == 0) {
            this.tableConfig.isCheckAll = false
        }
    }

    /**
     * 獲取已選的項(xiàng)
     * @author GR-05
     */
    getCheckItem(): T[] {
        return this.tableData$.value.filter(item => item[this.checkKey] == true && !item[this.disabledKey])
    }

}

我們?yōu)槭裁礇]有抽離成組件而是數(shù)據(jù)模型這么一個(gè)類上,主要是因?yàn)?,組件的樣式我們是不確定唯一性的,但數(shù)據(jù)和處理邏輯確是類似的,哪里地方要用到,就在哪個(gè)組件里new一個(gè)就好了;

其中BaseTableModel后面的T可以是所有你想在表格上渲染的任何一個(gè)model類,比如之前的ProductModel,頁面需求需要展示產(chǎn)品的表格列表,則

export class TableModel extends BaseTableModel {

    constructor() {
        super();
    }

}

那么最后你只需要將BaseTableModel里的tableData$數(shù)據(jù)next成處理好的ProdcuModel數(shù)組就好了。

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/98817.html

相關(guān)文章

  • 利用Dawn工程化工具實(shí)踐MobX數(shù)據(jù)流管理方案

    摘要:新的項(xiàng)目目錄設(shè)計(jì)如下放置靜態(tài)文件業(yè)務(wù)組件入口文件數(shù)據(jù)模型定義數(shù)據(jù)定義工具函數(shù)其中數(shù)據(jù)流實(shí)踐的核心概念就是數(shù)據(jù)模型和數(shù)據(jù)儲(chǔ)存。最后再吃我一發(fā)安利是阿里云業(yè)務(wù)運(yùn)營(yíng)事業(yè)部前端團(tuán)隊(duì)開源的前端構(gòu)建和工程化工具。 本文首發(fā)于阿里云前端dawn團(tuán)隊(duì)專欄。 項(xiàng)目在最初應(yīng)用 MobX 時(shí),對(duì)較為復(fù)雜的多人協(xié)作項(xiàng)目的數(shù)據(jù)流管理方案沒有一個(gè)優(yōu)雅的解決方案,通過對(duì)MobX官方文檔中針對(duì)大型可維護(hù)項(xiàng)目最佳實(shí)踐的...

    0x584a 評(píng)論0 收藏0
  • Backbone.js學(xué)習(xí)筆記(一)

    摘要:它通過數(shù)據(jù)模型進(jìn)行鍵值綁定及事件處理,通過模型集合器提供一套豐富的用于枚舉功能,通過視圖來進(jìn)行事件處理及與現(xiàn)有的通過接口進(jìn)行交互。 本人兼職前端付費(fèi)技術(shù)顧問,如需幫助請(qǐng)加本人微信hawx1993或QQ345823102,非誠(chéng)勿擾 1.為初學(xué)前端而不知道怎么做項(xiàng)目的你指導(dǎo) 2.指導(dǎo)并扎實(shí)你的JavaScript基礎(chǔ) 3.幫你準(zhǔn)備面試并提供相關(guān)指導(dǎo)性意見 4.為你的前端之路提供極具建設(shè)性的...

    FrancisSoung 評(píng)論0 收藏0
  • 如何設(shè)計(jì)大型網(wǎng)站前端 JavaScript 框架

    摘要:前端單元測(cè)試,推薦淘寶開源的工具,簡(jiǎn)單易用,支持眾多測(cè)試框架,也支持調(diào)試。這些也是設(shè)計(jì)前端框架時(shí)需要權(quán)衡的重要方面。最后,其實(shí)大型網(wǎng)站不一定要設(shè)計(jì)自己的前端框架,完全可以選用現(xiàn)有的框架。 有人在知乎上提問如何設(shè)計(jì)大型網(wǎng)站的前端 JavaScript 框架,有不少回答,其中得贊較多的兩個(gè)回答如下: 相對(duì)大型的項(xiàng)目在前端 JS 方面有幾個(gè)需要達(dá)成的目標(biāo): 1. 代碼邏輯分層 ...

    Yuanf 評(píng)論0 收藏0
  • 前端框架模式變遷

    摘要:現(xiàn)在在前端的框架都是的模式,還有像和之類的變種獨(dú)特的單向數(shù)據(jù)流框架。只要將數(shù)據(jù)流進(jìn)行規(guī)范,那么原來的模式還是大有可為的。我們可以來看一下,框架的圖示從圖中,我們可以看到形成了一條到,再到,之后是的,一條單向數(shù)據(jù)流。 前言 前端框架的變遷,體系架構(gòu)的完善,使得我們只知道框架,卻不明白它背后的道理。我們應(yīng)該抱著一顆好奇心,在探索框架模式的變遷過程中,體會(huì)前人的一些理解和思考 本篇將講述的是...

    ssshooter 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

最新活動(dòng)
閱讀需要支付1元查看
<