類似 easyui 中 datagrid 使用習慣的 element-ui 數據表格組件(el-datagrid)

背景

element-ui 中的 el-table 組件只提供了數據展示,而分頁功能作爲一個單獨的組件 el-pagination,並沒有像 Ant Design 一樣集成到 el-able 組件中,並且每一個數據列也都是一個單獨的組件 el-table-column

在開發過程中就出現了一個很明顯的問題:業務中的大部分數據表格功能都類似,數據列通常在3-6個不等,且都需要分頁,前端分頁與後端分頁的邏輯又不相同,這就導致了每次寫一個這樣數據表格功能,都需要至少複製粘貼很多 el-table-column 組件和一套實現分頁功能的代碼。寫代碼最惱火的就是要複製粘貼很多重複的代碼,一不小心就漏了些什麼,有木有……

結合我最早使用的 easyui 中的 datagrid 組件,在 element-ui的基礎上封裝一個能滿足大部分業務功能的 el-datagrid 組件,能大大的提高開發效率。

EasyUI 的 datagrid

接觸的第一個 UI 框架是 jQuery 版本的 EasyUI,雖然樣式是醜了一點,但個人覺得它的組件的封裝,對開發人員是很友好的,基本上每個組件都可以用一個 對象或數組 去動態配置,很符合 數據驅動 的思維。

功能

大部分的業務(增刪改查)中,數據表格通常有以下幾個功能:

  1. 數據展示
  2. 排序
  3. 對每一行的操作(查看、修改、刪除)
  4. 對整個數據表格的操作(新增、批量刪除)
  5. 分頁(前端 / 後端)
  6. 刷新數據

數據列配置(功能1、2、3 )

通常會從遠程加載數據,將數據列配置成 數組,數組的每一項匹配遠程數據中對象的屬性,替代寫多個 el-table-column 組件的麻煩。

遠程數據格式:

{
    data: [
        {
            name: 'lixiao 1',
            email: 'lixiao [email protected]'
        },
        ……
        {
            name: 'lixiao 12',
            email: 'lixiao [email protected]'
        }
    ],
    total: 12
}

數據列配置如下:

columns: [
    {
        label: '姓名',
        prop: 'name',
        sortable: true
    }, {
        label: '郵箱',
        prop: 'email',
        sortable: true
    }, {
        label: '操作',
        actions: [
            {
                label: '修改',
                prop: 'edit',
                type: 'warning',
                icon: 'el-icon-edit'
            }, {
                label: '刪除',
                prop: 'delete',
                type: 'danger',
                icon: 'el-icon-delete'
            }
        ]
    }
]

label 表示列對應的表頭,prop 表示列對應的遠程數據中對象的屬性,sortable 表示該列是否支持排序,actions 通常在最後一列,渲染一組操作按鈕,採用 this.$emit('rowClick', { row, prop }) 的方式,向父組件 App.vue 傳遞一個 rowClick 事件,參數是一個包含了 該行數據點擊按鈕的 prop(例如 edit / delete)的對象,在父組件中監聽 rowClick 事件,判斷 prop 的值即可做出不同的響應。

工具欄配置(功能4)

數據列配置能解決數據 增刪改查 中的刪、改、查,通常會在表格上方提供一組功能性按鈕,例如新增、導出(部分 / 全量)、批量刪除等功能,比較特殊的是批量刪除這種功能需要獲取到已經選中的行的數據。

toolbar: [
    {
        label: '新增',
        prop: 'add',
        type: 'primary',
        icon: 'el-icon-plus',
    }, {
        label: '刪除多行',
        prop: 'delete',
        type: 'danger',
        icon: 'el-icon-delete',
        usableAfterSelect: true
    }
]

同樣使用 this.$emit('toolbarClick', { rows, prop }) 的方式向父組件傳遞一個 toolbarClick 事件,不同的是,rows 是一個包含了多行數據的數組(當然也可能是一個空數組),父組件中監聽 toolbarClick 事件,判斷 prop 值和 rows 長度即可做出不同的響應。

對於需要 至少選擇一行 才能進行操作的功能,參考了 Ant Design 例子中的交互,設置 usableAfterSelect 屬性爲 true 之後,選中至少一行之前按鈕不可用。

clipboard.png

clipboard.png

分頁(功能5)

前端分頁

第一次獲取數據之後,切換頁碼、切換每頁數量只需要利用 slice 截取原始數據數組中對應數量的數據。

後端分頁

每次切換頁碼和切換每頁數量都需要重新獲取數據,將返回的全部數據都作爲要顯示的原始數據。

// ElDatagrid.vue
// this.index 表示顯示的數據的序號,表頭爲 #

<el-table :data="showData" />

computed: {
    showData() {
        if (this.clientPagination) {
            // 若客戶端分頁,則根據頁碼和每頁數量 截取相應的數據
            return this.data.slice().splice(this.index - 1, this.pageSize);
        } else {
            // 若服務端分頁,則直接顯示獲取到的數據
            return this.data.slice();
        }
    }
},

刷新數據(功能6)

刷新數據指僅刷新數據表格的數據,而不是刷新整個頁面。而觸發刷新的操作往往是由父組件發起的,就變成了,如何讓父組件通知子組件重新發請求獲取數據。

實現這個功能我嘗試了好幾種方法:

  • 最難看的 bus 中央事件總線。每個子組件實例都與父組件有一個不衝突的事件名做關聯,用起來不方便
  • 在子組件中 watch 一個傳遞過來的 prop 值的變化,那父組件需要更新數據的時候還是需要改變那個傳遞給子組件的值,嗯,new Date() 肯定是一直在變的……使用仍然不是很方便
  • 父組件中通過 $refs 訪問子組件,調用子組件的方法。原來有這麼簡單又好用的方法
<el-datagrid ref="datagrid" />

methods: {
    reloadDatagrid() {
        this.$refs['datagrid'].reload();
    }
}

完整的 ElDatagrid 組件和使用 demoAPI 文檔:https://github.com/lixiao564/...

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章