01、什麼是列舉Enum?
列舉Enum
是在多種語言中都有的一種資料型別,用於表示一組特定相關的常量資料集合,如性別(男、女)、資料狀態(可用、禁用)、垂直對齊(頂端、居中、底部)、星期等。特點是資料值固定,不會變,儲存和顯示的內容不同。
然而在JavaScript中並沒有列舉Enum
型別,TypeScript算是有(本文中暫沒用用TS的列舉)。在前端專案中還是會用到經常用到這型別資料的,本文就對列舉做一個通用封裝,並進行儘量全域性的總結。
先來看看最常用的性別:
Text文字(介面顯示) | 編碼(編碼、傳輸、儲存使用) | 數字值(儲存使用) |
---|---|---|
男 | male/man/M | 1 |
女 | female/woman/F | 2 |
其他 | other | 3 |
❓你的系統中性別用的什麼儲存的呢?
- 在UI上顯示為
Text
文字描述,如表格、單選項。 - 傳輸或儲存時,一般會用一個有意義的字元編碼,或者數字,兩種方式都有也都可以。
- 如果資料量少,可以用字元編碼,如M(男)、Male(男),可讀性更好,就是佔用空間比數字型別多。
- 推薦採用短整形數字表示,儲存空間更小,採用一個位元組的最小整形即可(值為0到255)。
針對性別的列舉值,其實是有國家標準的,國標中就是用的整數值標識。
📢參考國標:GB/T 2261.1-2003 個人基本資訊分類與程式碼 第1部分:人的性別程式碼(可線上預覽),早在2003年就頒佈了。
SO,我們用列舉的主要目的就是處理UI、儲存(編碼傳輸)的值轉換問題,兼顧顯示的友好、儲存的效能。在一些面嚮物件語言如JAVA、C#中使用體驗更佳,支援列舉值的程式碼提示輸入,避免硬編碼,還可以用位運算儲存多個值(算是稍微高階一點的玩法了)。
02、前端應用場景
1、表格資料繫結時,需要顯示使用者易懂的(中文)描述資訊,用不同顏色樣式區分,而後端返回的JSON資料中可能是編碼值M/F,或1/2
。
2、直接顯示列舉值的(中文)描述資訊+樣式,如elementUI中的<el-tag>
元件。
3、作為表單元件的繫結資料來源,如下拉選擇、單選組、複選組表單元件。
03、封裝EnumFactory
3.1、EnumFactory
設計一個列舉工廠 EnumFactory(enumFactory.js),統一建立列舉所需的屬性和方法:
- 引數
enumObj
為要傳入的列舉基礎定義:- 標準模式(
key:{text:'',type:''}
)示例:{ 1: { text: '男', type: 'priary' }, 2: { text: '女', type: 'warning' }}
- 簡寫模式(
key:text
),會被自動轉換為標準模式,示例:{ left: '左對齊', center: '居中', right: '右對齊' }
- **value **資料結構約定:
value
值部分約定text
為文字描述,type
為樣式類別(elementUI
中的狀態type:success/info/warning/danger
),其他可隨意。
- 標準模式(
- 引數
keyParseFunc
為key的轉換函式,預設key為字串,keyParseFunc
預設值為null(不轉換),如果key為整數,則需要傳入轉換函式(傳入JS內建parseInt
即可)。 - 返回值繼承自引數
enumObj
,擴充套件了屬性 keys、values、formatter。**keys**
,列舉key陣列,如[0,1,2]
、["male","female","other"]
。**values**
,值陣列,包含了key,結構[{key:'',text:'',type:''}]
。**formatter**
:elementUI中表格繫結列舉資料文字的formatter函式。
/**
* 列舉建立工廠(建構函式),擴充套件列舉物件:keys、values(含key值的[{key,text,type}])、formatter。
* @param {*} enumObj 列舉值,支援標準模式{key:{text,type},},簡單模式{key:text,}(會自動轉換為標準模式)
* @param {*} keyParseFunc key的轉換函式,預設null,如果key為整數則傳 parseInt
*/
export default function EnumFactory(enumObj, keyParseFunc = null) {
//複製(繼承)enumObj
Object.assign(this, enumObj)
// keys:列舉的key集合[key]
Object.defineProperty(this, 'keys', {
value: keyParseFunc ? Object.keys(enumObj).map(s => keyParseFunc(s)) : Object.keys(enumObj)
})
// 處理 values
let values = []
const ovalues = Object.values(enumObj)
// 主要區分下value是簡單型別(字串)還是物件型別
if (typeof ovalues[0] === 'string') {
ovalues.forEach((text, index) => {
const obj = { key: this.keys[index], text }
values.push(obj)
this[this.keys[index]] = obj
})
}
else {
ovalues.forEach((item, index) => {
item.key = this.keys[index]
values.push(item)
})
}
// 設定values屬性
Object.defineProperty(this, 'values', { value: values })
// formatter:element中表格繫結列舉資料文字的formatter函式
// r、c為行列,可傳入null
Object.defineProperty(this, 'formatter', {
value: function(r, c, value) {
return values.filter(v => v.key == value || v.text == value)[0]?.text || 'notfound'
}
})
//列舉定義的資料都是常量,不可修改,凍結一下
Object.freeze(this)
}
3.2、基於EnumFactory定義列舉值
建立一個enums.js
存放常用列舉常量:
- 性別列舉物件(key為整數)
- 使用狀態
- 對齊方式
import EnumFactory from "@/utils/enumFactory";
/**
* 性別列舉物件(key為整數)
*/
export const enumGender = new EnumFactory({
1: { text: '男', type: 'priary' },
2: { text: '女', type: 'warning' },
9: { text: '其他', type: 'info' },
},parseInt)
/**
* 使用狀態
*/
export const enumUse = new EnumFactory({
enable: { text: '啟用', type: 'success' },
disable: { text: '禁用', type: 'danger' }
})
// 對齊方式
const enumAlign = new EnumFactory({ left: '左', middle: '中', right: '右' })
enumGender
的結構如下:
enumGender.keys
:[0,1,2]
enumGender.values
:[{"text":"其他","type":"info","key":0},{"text":"男","type":"priary","key":1},{"text":"女","type":"warning","key":2}]
04、ElementUI中使用
1、表格資料繫結時,顯示使用者易懂的(中文)描述資訊,用不同顏色樣式區分。使用自template
模板自定義,或者formatter
函式,格式化函式就不支援樣式狀態了。
🚩關鍵程式碼:enumGender[scope.row.gender]?.text
<el-table :data="table">
<el-table-column label="姓名" prop="name" width="220px"></el-table-column>
<el-table-column label="性別" prop="gender" align="center" width="120px">
<template slot-scope="scope">
<el-tag :type="enumGender[scope.row.gender]?.type">{{ enumGender[scope.row.gender]?.text }}</el-tag>
</template>
</el-table-column>
<el-table-column label="方向" prop="align" :formatter="enumAlign.formatter" width="120px"></el-table-column>
<el-table-column label="狀態" prop="use" align="center" width="120px">
<template slot-scope="scope">
<el-tag :type="enumUse[scope.row.use]?.type">{{ enumUse[scope.row.use]?.text }}</el-tag>
</template>
</el-table-column>
</el-table>
效果:
2、直接顯示列舉值的(中文)描述資訊+樣式,用type
來繫結狀態樣式。
<el-form-item label="狀態標籤-all">
<el-tag v-for="tag in enumGender.values" :key="tag.key" :type="tag.type" style="margin-right: 10px;">
{{tag.text }}
</el-tag>
</el-form-item>
<el-form-item label="狀態標籤-值">
<el-tag :type="enumGender[value]?.type">{{ enumGender[value]?.text }} : {{ value }}</el-tag>
</el-form-item>
效果:
3、作為表單元件的繫結資料來源,如下拉選擇、單選組、複選組表單元件。
🚩用enumAlign.values作為源來繫結
<el-form-item label="下拉選擇">
<el-select v-model="value">
<el-option v-for="e in enumAlign.values" :key="e.key" :value="e.key" :label="e.text"></el-option>
</el-select>
</el-form-item>
<el-form-item label="單選組1">
<el-radio-group v-model="value">
<el-radio-button v-for="item in enumAlign.values" :key="item.key" :label="item.key">{{ item.text }}</el-radio-button>
</el-radio-group>
</el-form-item>
<el-form-item label="單選組2">
<el-radio-group v-model="value">
<el-radio v-for="item in enumAlign.values" :key="item.key" :label="item.key">{{ item.text }}</el-radio>
</el-radio-group>
</el-form-item>
效果:
總結
其實本質上就是設計一個標準的資料結構,能夠方便的獲取所有列舉資料項,然後根據值快速獲取顯示的文字。
參考資料
- 性別國標:GB/T 2261.1-2003 個人基本資訊分類與程式碼 第1部分:人的性別程式碼
- 開源專案庫:kvue-admin
- 文中使用示例原始碼:enums.vue
©️版權申明:版權所有@安木夕(kanding),本文內容僅供學習,歡迎指正、交流,轉載請註明出處!
原文編輯地址:https://www.yuque.com/kanding