優雅使用前端枚舉Enum,符合國標的那種!

image.png

01、什麼是枚舉Enum?

枚舉Enum是在多種語言中都有的一種數據類型,用於表示一組特定相關的常量數據集合,如性別(男、女)、數據狀態(可用、禁用)、垂直對齊(頂端、居中、底部)、星期等。特點是數據值固定,不會變,存儲和顯示的內容不同。

然而在JavaScript中並沒有枚舉Enum類型,TypeScript算是有(本文中暫沒用用TS的枚舉)。在前端項目中還是會用到經常用到這類型數據的,本文就對枚舉做一個通用封裝,並進行儘量全局的總結。

先來看看最常用的性別:

Text文字(界面顯示) 編碼(編碼、傳輸、存儲使用) 數字值(存儲使用)
male/man/M 1
female/woman/F 2
其他 other 3

❓你的系統中性別用的什麼存儲的呢?

  • 在UI上顯示爲Text文字描述,如表格、單選項。
  • 傳輸或存儲時,一般會用一個有意義的字符編碼,或者數字,兩種方式都有也都可以。
  • 如果數據量少,可以用字符編碼,如M(男)、Male(男),可讀性更好,就是佔用空間比數字類型多。
  • 推薦採用短整形數字表示,存儲空間更小,採用一個字節的最小整形即可(值爲0到255)。

image.png

針對性別的枚舉值,其實是有國家標準的,國標中就是用的整數值標識。

📢參考國標:GB/T 2261.1-2003 個人基本信息分類與代碼 第1部分:人的性別代碼(可在線預覽),早在2003年就頒佈了。

image.png

SO,我們用枚舉的主要目的就是處理UI、存儲(編碼傳輸)的值轉換問題,兼顧顯示的友好、存儲的性能。在一些面嚮對象語言如JAVA、C#中使用體驗更佳,支持枚舉值的代碼提示輸入,避免硬編碼,還可以用位運算存儲多個值(算是稍微高級一點的玩法了)。


02、前端應用場景

人員選擇-選擇bug2.gif

1、表格數據綁定時,需要顯示用戶易懂的(中文)描述信息,用不同顏色樣式區分,而後端返回的JSON數據中可能是編碼值M/F,或1/2

image.png

2、直接顯示枚舉值的(中文)描述信息+樣式,如elementUI中的<el-tag>組件。

image.png

3、作爲表單組件的綁定數據源,如下拉選擇、單選組、複選組表單組件。

image.png


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的結構如下:

image.png

  • 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>

效果:

image.png

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>

效果:

image.png

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>

效果:

image.png


總結

其實本質上就是設計一個標準的數據結構,能夠方便的獲取所有枚舉數據項,然後根據值快速獲取顯示的文本。


參考資料


©️版權申明:版權所有@安木夕(kanding),本文內容僅供學習,歡迎指正、交流,轉載請註明出處!
原文編輯地址:https://www.yuque.com/kanding

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