激情六月丁香婷婷|亚洲色图AV二区|丝袜AV日韩AV|久草视频在线分类|伊人九九精品视频|国产精品一级电影|久草视频在线99|在线看的av网址|伊人99精品无码|午夜无码视频在线

高校合作1:010-59833514 ?咨詢電話:400-810-1418 服務(wù)與監(jiān)督電話:400-810-1418轉(zhuǎn)接2

「摸魚神器」UI庫秒變LowCode工具——列表篇(一)設(shè)計與實現(xiàn)

發(fā)布時間:2024-04-16 14:30:22 瀏覽量:236次

內(nèi)容摘要:

  • 需求分析
  • 定義 interface
  • 定義 json 文件
  • 定義列表控件的 props
  • 基于 el-table 封裝,實現(xiàn)依賴 json 渲染
  • 實現(xiàn)內(nèi)置功能:選擇行(單選、多選),格式化、鎖定等。
  • 使用 slot 實現(xiàn)自定義擴展
  • 做個工具維護 json 文件(下篇介紹)

管理后臺里面,列表是一個常用的功能,UI庫提供了列表組件和分頁組件實現(xiàn)功能。雖然功能強大,也很靈活,只是還不能稱為低代碼,不過沒關(guān)系,我們可以寫點代碼讓UI庫變?yōu)槊~神器!

本篇介紹列表的設(shè)計思路和封裝方式。

需求分析

如果基于原生HTML來實現(xiàn)顯示數(shù)據(jù)列表的功能的話,那么需考慮如何創(chuàng)建 table,如何設(shè)置css等。
如果直接使用UI庫的話,那么可以簡單很多,只需要設(shè)置各種屬性,然后綁定數(shù)據(jù)即可。
以 el-table 為例:

  <el-table
    :data="tableData"
    border
    stripe
    style="width: 100%"
  >
    <el-table-column prop="date" label="Date" width="180" />
    <el-table-column prop="name" label="Name" width="180" />
    <el-table-column prop="address" label="Address" />
  </el-table>

設(shè)置好屬性、記錄集合,然后設(shè)置列(el-table-column)即可。
這樣一個列表就搞定了,再加上 el-pagination 分頁組件,編寫一些代碼即可實現(xiàn)分頁的功能。

如果只是一個列表的話,這種方式?jīng)]啥問題,但是管理后臺項目,往往需要n個列表,而每個列表都大同小異,如果要一個一個手?jǐn)]出來,那就有點麻煩了。

那么如何解決呢?我們可以參考低代碼,基于 el-talbe 封裝一個列表控件,
實現(xiàn)依賴 json 動態(tài)渲染列表,同時支持自定義擴展。

定義 interface

最近開始學(xué)習(xí) Typescript,發(fā)現(xiàn)了一個現(xiàn)象,如果可以先定義好類型,那么代碼就可以更清晰的展現(xiàn)出來。

另外 Vue3 的最新文檔,也采用了通過 interface 來介紹API功能的方式,所以我們也可以借鑒一下。

依據(jù) el-table 的屬性,定義列表控件屬性的 interface。

Vue3 的 props 有一套約束方式,這個似乎和TS的方式有點沖突,沒想出了更好的方法(option API 和 script setup兩種定義props的方式,都有不足 ),所以只好做兩個 interface,一個用于定義組件的 props ,一個用于取值。

  • IGridPropsComp:定義組件的 props
/**
 * 列表控件的屬性的描述,基于el-table
 */
export interface IGridPropsComp {
  /**
   * 模塊ID,number | string
   */
  moduleId: IPropsValidation,
  /**
   * 主鍵字段的名稱 String,對應(yīng) row-key
   */
  idName: IPropsValidation,
  /**
   * table的高度, Number
   */
  height: IPropsValidation,
  /**
   * 列(字段)顯示的順序 Array<number|string>
   */
  colOrder: IPropsValidation,
  /**
   * 斑馬紋,Boolean
   */
  stripe: IPropsValidation,
  /**
   * 縱向邊框,Boolean
   */
  border: IPropsValidation,
  /**
   * 列的寬度是否自撐開,Boolean
   */
  fit: IPropsValidation,
  /**
   * 要高亮當(dāng)前行,Boolean
   */
  highlightCurrentRow: IPropsValidation,
  /**
   * 鎖定的列數(shù) Number,設(shè)置到 el-table-column 的 fixed
   */
  fixedIndex: IPropsValidation,
  /**
   * table的列的 IGridItem
   * * id: number | string,
   * * colName: string, 字段名稱
   * * label: string, 列的標(biāo)簽、標(biāo)題
   * * width: number, 列的寬度
   * * align: EAlign, 內(nèi)容對齊方式
   * * headerAlign: EAlign 列標(biāo)題對齊方式
   */
  itemMeta: IPropsValidation, // 
  /**
   * 記錄選擇的行:IGridSelection
   * * dataId: '', 單選ID number 、string
   * * row: {}, 單選的數(shù)據(jù)對象 {}
   * * dataIds: [], 多選ID []
   * * rows: [] 多選的數(shù)據(jù)對象 []
   */
  selection: IPropsValidation, 
    
  /**
   * 綁定的數(shù)據(jù) Array, 對應(yīng) data
   */
  dataList: IPropsValidation

  // 其他擴展屬性
  [propName: string]: IPropsValidation

}
  • moduleId:模塊ID,一個模塊菜單只能有一個列表,菜單可以嵌套。
  • itemMeta:列的屬性集合,記錄列表的列的屬性。
  • selection:記錄列表的單選、多選的 row。
  • dataList:顯示的數(shù)據(jù),對應(yīng) el-table 的 data
  • 其他:對應(yīng) el-table 的屬性

IGridPropsComp 的作用是,約束列表控件需要設(shè)置哪些屬性,屬性的具體類型,就無法在這里約束了。

  • IPropsValidation (不知道vue內(nèi)部有沒有這樣的 interface)
/**
 * vue 的 props 的驗證的類型約束
 */
export interface IPropsValidation {
  /**
   * 屬性的類型,比較靈活,可以是 String、Number 等,也可以是數(shù)組、class等
   */
  type: Array<any> | any,
  /**
   * 是否必須傳遞屬性
   */
  required?: boolean,
  /**
   * 自定義類型校驗函數(shù)(箭頭函數(shù)),value:屬性值
   */
  validator?: (value: any) => boolean,
  /**
   * 默認(rèn)值,可以是值,也可以是函數(shù)(箭頭函數(shù))
   */
  default?: any
}

取 props 用的 interface

IGridPropsComp 無法約束屬性的具體類型,所以只好再做一個 interface。

  • IGridProps
/**
 * 列表控件的屬性的類型,基于el-table
 */
 export interface IGridProps {
  /**
   * 模塊ID,number | string
   */
  moduleId: number | string,
  /**
   * 主鍵字段的名稱 String,對應(yīng) row-key
   */
  idName: String,
  /**
   * table的高度, Number
   */
  height: number,
  /**
   * 列(字段)顯示的順序 Array<number|string>
   */
  colOrder: Array<number|string>,
  /**
   * 斑馬紋,Boolean
   */
  stripe: boolean,
  /**
   * 縱向邊框,Boolean
   */
  border: boolean,
  /**
   * 列的寬度是否自撐開,Boolean
   */
  fit: boolean,
  /**
   * 要高亮當(dāng)前行,Boolean
   */
  highlightCurrentRow: boolean,
  /**
   * 鎖定的列數(shù) Number,設(shè)置到 el-table-column 的 fixed
   */
  fixedIndex: number,
  /**
   * table的列的 Object< IGridItem >
   * * id: number | string,
   * * colName: string, 字段名稱
   * * label: string, 列的標(biāo)簽、標(biāo)題
   * * width: number, 列的寬度
   * * align: EAlign, 內(nèi)容對齊方式
   * * headerAlign: EAlign 列標(biāo)題對齊方式
   */
  itemMeta: {
    [key:string | number]: IGridItem
  }, // 
  /**
   * 選擇行的情況:IGridSelection
   * * dataId: '', 單選ID number 、string
   * * row: {}, 單選的數(shù)據(jù)對象 {}
   * * dataIds: [], 多選ID []
   * * rows: [] 多選的數(shù)據(jù)對象 []
   */
  selection: IGridSelection, 
    
  /**
   * 綁定的數(shù)據(jù) Array, 對應(yīng) data
   */
  dataList: Array<any>

  // 其他擴展屬性
  [propName: string]: any
}

對比一下就會發(fā)現(xiàn),屬性的類型不一樣。因為定義 props 需要使用一套特定的對象格式,而使用 props 的時候需要的是屬性自己的類型。

理想情況下,應(yīng)該可以在 script setup 里面,引入外部文件 定義的 interface ,然后設(shè)置給組件的 props,但是到目前為止還不支持,只能在( script setup方式的)組件內(nèi)部定義 props。希望早日支持,支持了就不會這么糾結(jié)和痛苦了。

依據(jù) el-table-column 定義列屬性的 interface。

  • IGridItem:列表里面列的屬性
/**
 * 列的屬性,基于 el-table-column
 */
export interface IGridItem {
  /**
   * 字段ID、列ID
   */
  id: number | string,
  /**
   * 字段名稱
   */
  colName: string,
  /**
   * 列的標(biāo)簽、標(biāo)題
   */
  label: string,
  /**
   * 列的寬度
   */
  width: number,
  /**
   * 內(nèi)容對齊方式 EAlign
   */
  align: EAlign,
  /**
   * 列標(biāo)題對齊方式
   */
  headerAlign: EAlign,

  // 其他擴展屬性
  [propName: string]: any
}

還是需要擴展屬性的,因為這里只是列出來目前需要的屬性,el-table-column 的其他屬性、方法還有很多,而且以后也可能會新增。

這個屬性不是直接設(shè)置給組件的 props,所以不用定義兩套了。

對齊方式的枚舉

枚舉可以理解為常量,定義之后可以避免低級錯誤,避免手滑。

  • EAlign
export const enum EAlign {
  left = 'left',
  center = 'center',
  right = 'right'
}

選擇記錄的 interface。

列表可以單選也可以多選,el-table 在默認(rèn)情況下似乎是二選一,覺得有點不方便,為啥不能都要?

  • 單選:鼠標(biāo)單一任意一行就是單選;(清空其他已選項)
  • 多選:單擊第一列的(多個)復(fù)選框,就是多選;

這樣用戶就可以愉快的想單選就單選,想多選就多選了。

  • IGridSelection
/**
 * 列表里選擇的數(shù)據(jù)
 */
export interface IGridSelection {
  /**
   * 單選ID number 、string
   */
  dataId: number | string,
  /**
   * 單選的數(shù)據(jù)對象 {}
   */
  row: any,
  /**
   * 多選ID []
   */
  dataIds: Array<number | string>,
  /**
   * 多選的數(shù)據(jù)對象 []
   */
  rows: Array<any>
}

其實我覺得只記錄ID即可,不過既然 el-talble 提供的 row,那么還是都記錄下來吧。

定義 json 文件

接口定義好之后,我們可以依據(jù) interface 編寫 json 文件:

{
  "moduleId": 142,
  "height": 400,
  "idName": "ID",
  "colOrder": [
    90,  100, 101 
  ],
  "stripe": true,
  "border": true,
  "fit": true,
  "highlightCurrentRow": true,
  "highlight-current-row": true,
  "itemMeta": {
    "90": {
      "id": 90,
      "colName": "kind",
      "label": "分類",
      "width": 140,
      "title": "分類",
      "align": "center",
      "header-align": "center"
    },
    "100": {
      "id": 100,
      "colName": "area",
      "label": "多行文本",
      "width": 140,
      "title": "多行文本",
      "align": "center",
      "header-align": "center"
    },
    "101": {
      "id": 101,
      "colName": "text",
      "label": "文本",
      "width": 140,
      "title": "文本",
      "align": "center",
      "header-align": "center"
    } 
  }
}

  • 為什么直接設(shè)置 json 文件而不是 js 對象呢?
    因為對象會比較長,如果是代碼形式的話,那還不如直接使用UI庫組件來的方便呢。
  • 你可能又會問了,既然直接用 json文件,為啥還要設(shè)計 interface 呢?
    當(dāng)然是為了明確各種類型,interface 可以當(dāng)做文檔使用,另外封裝UI庫的組件的時候,也可以用到這些 interface。使用列表控件的時候也可以使用這些 interface。

其實json文件不用手動編寫,而是通過工具來編寫和維護。

定義列表控件的 props

封裝組件之前需要先定義一下組件需要的 props:

  • props-grid.ts
import type { PropType } from 'vue'

import type {
  IGridProps,
  IGridItem,
  IGridSelection
} from '../types/50-grid'

/**
 * 表單控件需要的屬性propsForm
 */
export const gridProps: IGridProps = {
  /**
   * 模塊ID,number | string
   */
  moduleId: {
    type: Number,
    required: true
  },
  /**
   * 主鍵字段的名稱
   */
  idName: {
    type: String,
    default: 'ID'
  },
  /**
   * 字段顯示的順序
   */
  colOrder: {
    type: Array as PropType<Array<number | string>>,
    default: () => []
  },
  /**
   * 鎖定的列數(shù)
   */
  fixedIndex: {
    type: Number,
    default: 0
  },
  /**
   * table的列的 meta
   */
  itemMeta: {
    type: Object as PropType<{
      [key:string | number]: IGridItem
    }>
  },
  /**
   * 選擇的情況 IGridSelection
   */
  selection: {
    type: Object as PropType<IGridSelection>,
    default: () => {
      return {
        dataId: '', // 單選ID number 、string
        row: {}, // 單選的數(shù)據(jù)對象 {}
        dataIds: [], // 多選ID []
        rows: [] // 多選的數(shù)據(jù)對象 []
      }
    }
  },
  /**
   * 綁定的數(shù)據(jù)
   */
  dataList: {
    type: Array as PropType<Array<any>>,
    default: () => []
  },
  其他略。。。
}

按照 Option API 的方式設(shè)置 props 的定義,這樣便于共用屬性的定義(好吧似乎也沒有需要共用的地方,不過我還是喜歡把 props 的定義寫在一個單獨的文件里)。

封裝列表控件

定義好 json 、props之后,我們基于 el-table 封裝列表控件:

  • template 模板
  <el-table
    ref="gridRef"
    v-bind="$attrs"
    :data="dataList"
    :height="height"
    :stripe="stripe"
    :border="border"
    :fit="fit"
    :highlight-current-row="highlightCurrentRow"
    :row-key="idName"
    @selection-change="selectionChange"
    @current-change="currentChange"
  >
    <!--多選框,實現(xiàn)多選功能-->
    <el-table-column
      type="selection"
      width="55"
      align="center"
      header-align="center"
      @click="clickCheck"
    >
    </el-table-column>
    <!--依據(jù) json 渲染的字段列表-->
    <el-table-column
      v-for="(id, index) in colOrder"
      :key="'grid_list_' + index + '_' + id"
      v-bind="itemMeta[id]"
      :column-key="'col_' + id"
      :fixed="index < fixedIndex"
      :prop="itemMeta[id].colName"
    >
    </el-table-column>
  </el-table>

設(shè)置 type="selection"列,實現(xiàn)多選的功能。
使用 v-for 的方式,遍歷出動態(tài)列。
設(shè)置 :fixed="index < fixedIndex",實現(xiàn)鎖定左面列的功能。

  • js 代碼
  import { defineComponent, ref } from 'vue'
  // 列表控件的屬性 
  import { gridProps } from '../map'

  /**
   * 普通列表控件
   */
  export default defineComponent({
    name: 'nf-elp-grid-list',
    inheritAttrs: false,
    props: {
      ...gridProps // 解構(gòu)共用屬性
    },
    setup (props, ctx) {
      // 獲取 el-table 
      const gridRef =  ref(null)
 
      return {
        gridRef
      }
    }
  })

把 props 的定義放在單獨的 ts文件 里面,組件內(nèi)部的代碼就可以簡潔很多。

實現(xiàn)內(nèi)置功能

可以按照自己的喜好,設(shè)置一些內(nèi)部功能,比如單選/多選的功能,格式化的功能等。

  • 定義控制函數(shù) controller.ts
import type { ElTable } from 'element-plus'

// 列表控件的屬性 
import type { IGridProps } from '../map'

export interface IRow {
 [key: string | number]: any
}

/**
* 列表的單選和多選的事件
* @param props 列表組件的 props
* @param gridRef el-table 的 $ref
*/
export default function choiceManage<T extends IGridProps, V extends typeof ElTable>(props: T, gridRef: V) {
 // 是否單選觸發(fā)
 let isCurrenting = false
 // 是否多選觸發(fā)
 let isMoring = false

 // 單選
 const currentChange = (row: IRow) => {
   if (isMoring) return // 多選代碼觸發(fā)
   if (!row) return // 清空

   if (gridRef.value) {
     isCurrenting = true
     gridRef.value.clearSelection() // 清空多選
     gridRef.value.toggleRowSelection(row) // 設(shè)置復(fù)選框
     gridRef.value.setCurrentRow(row) // 設(shè)置單選
     // 記錄
     props.selection.dataId = row[props.idName]
     props.selection.dataIds = [ row[props.idName] ]
     props.selection.row = row
     props.selection.rows = [ row ]

     isCurrenting = false
   }
 }

 // 多選
 const selectionChange = (rows: Array<IRow>) => {
   if (isCurrenting) return
   // 記錄
   if (typeof props.selection.dataIds === 'undefined') {
     props.selection.dataIds = []
   }
   props.selection.dataIds.length = 0 // 清空
   // 設(shè)置多選
   rows.forEach((item: IRow) => {
     if (typeof item !== 'undefined' && item !== null) {
       props.selection.dataIds.push(item[props.idName])
     }
   })
   props.selection.rows = rows
   // 設(shè)置單選
   switch (rows.length) {
     case 0:
       // 清掉單選
       gridRef.value.setCurrentRow()
       props.selection.dataId = ''
       props.selection.row = {}
       break
     case 1:
       isMoring = true
       // 設(shè)置新單選
       gridRef.value.setCurrentRow(rows[0])
       isMoring = false
       props.selection.row = rows[0]
       props.selection.dataId = rows[0][props.idName]
       break
     default:
       // 去掉單選
       gridRef.value.setCurrentRow()
       props.selection.row = rows[rows.length - 1]
       props.selection.dataId = props.selection.row[props.idName]
   }
 }

 return {
   currentChange, // 單選
   selectionChange // 多選
 }
}
  • 列表控件的 setup 里調(diào)用
setup (props, ctx) {
  // 獲取 el-table 
  const gridRef = ref<InstanceType<typeof ElTable>>()

  // 列表選項的事件
  const {
    currentChange, // 單選
    selectionChange // 多選
  } = choiceManage(props, gridRef)

  return {
    selectionChange, // 多選
    currentChange, // 單選
    gridRef // table 的 dom
  }
}

這里有一個“度”的問題:

  • el-table 完全通過 slot 的方式實現(xiàn)各種功能,這種方法的特點是:非常靈活,可以各種組合;缺點是比較繁瑣。
    而我們需要尋找到一個適合的“折中點”,顯然這個折中點很難統(tǒng)一,這也是過渡封裝帶來的問題。
  • 不能遇到新的需求,就增加內(nèi)部功能,這樣就陷入了《人月神話》里說的“焦油坑”,進去了就很難出來。

這也是低代碼被詬病的因素。

支持?jǐn)U展

那么如何找到這個折中點呢?可以按照 “開閉原則”,按照不同的需求,設(shè)置多個不同功能的列表控件,使用 slot 實現(xiàn)擴展功能?;蛘吒纱喔臑橹苯邮褂?el-table 的方式。(要靈活,不要一刀切)

比如簡單需求,不需要擴展功能的情況,設(shè)置一個基礎(chǔ)列表控件:nf-grid。
需要擴展列的情況,設(shè)置一個可以擴展的列表控件:nf-grid-slot。

如果需要多表頭、樹形數(shù)據(jù)等需求,可以設(shè)置一個新的列表控件,不過需要先想想,是不是直接用 el-table 更方便。

要不要新增一個控件,不要慣性思維,而要多方面全局考慮。

這里介紹一下支持 slot 擴展的列表控件的封裝方式:

  <el-table
    ref="gridDom"
    v-bind="$attrs"
    size="mini"
    style="width: 100%"
    :data="dataList"
    :height="height"
    :stripe="stripe"
    :border="border"
    :fit="fit"
    :highlight-current-row="highlightCurrentRow"
    :current-row-key="idName"
    :row-key="idName"
    @selection-change="selectionChange"
    @current-change="currentChange"
  >
    <!--顯示選擇框-->
    <el-table-column
      type="selection"
      width="55">
    </el-table-column>
    <!--顯示字段列表-->
    <template
      v-for="(id, index) in colOrder"
      :key="'grid_list_' + index + '_' + id"
    >
      <!--檢查插槽里是否包含 字段名,作為判斷依據(jù)-->
      <!--不帶插槽的列-->
      <el-table-column
        v-if="!(slotsKey.includes(itemMeta[id].colName))"
        :fixed="index < fixedIndex"
        v-bind="itemMeta[id]"
        :prop="itemMeta[id].colName"
        :min-width="50"
      >
      </el-table-column>
      <!--帶插槽的列-->
      <el-table-column  v-else
        v-bind="itemMeta[id]"
      >
        <template #default="scope">
          <!--讀取外部插槽內(nèi)容,并且傳遞 scope -->
          <slot :name="itemMeta[id].colName" v-bind="scope"></slot>
        </template>
      </el-table-column>
    </template>
  </el-table>

模板部分,首先判斷一下是否需要使用 slot,做一個分支。
需要使用 slot 的列,通過 <template #default="scope"> 設(shè)置 slot。

  • 代碼部分
  import { defineComponent, ref } from 'vue'
  // 表單控件的屬性 
  import { gridProps } from '../map'
  import choiceManage from './controller'

  export default defineComponent({
    name: 'nf-elp-grid-slot',
    inheritAttrs: false,
    props: {
      ...gridProps
    },
    setup (props, ctx) {
      // 記錄插槽 的 名稱
      const slots = ctx.slots
      const slotsKey = Object.keys(slots)
 
      // 列表選項的事件
      const {
        currentChange, // 單選
        selectionChange // 多選
      } = choiceManage(props, gridRef)

      return {
        slotsKey,
        selectionChange, // 多選
        currentChange // 單選
      }
    }
  })

一般列表的使用方法

封裝之后,使用起來就很方便了,引入 json文件,設(shè)置屬性即可。

  • template
  <nf-grid
    v-bind="gridMeta"
    :dataList="dataList"
    :selection="selection"
    size="small"
  />

是不是簡單多了。

  • 代碼部分
  import { defineComponent, reactive } from 'vue'
  import { nfGrid, createDataList } from '../../../../lib-elp/main'
  import _gridMeta from '../../grid/grid.json'
  import _formMeta from '../../form/form.json'
 
  export default defineComponent({
    name: 'nf-elp-grid-page',
    components: {  nfGrid  },
    setup(props) {
      // 不需要動態(tài)改變的話,可以不使用 reactive。
      const gridMeta = reactive(_gridMeta)
      // 設(shè)置選擇的行
      const selection = reactive({
        dataId: '', // 單選ID number 、string
        row: {}, // 單選的數(shù)據(jù)對象 {}
        dataIds: [], // 多選ID []
        rows: [] // 多選的數(shù)據(jù)對象 []
      })
      // 設(shè)置記錄集。
      const dataList = reactive(_dataList)

      return {
        dataList,
        selection,
        gridMeta
      }
    }
  })

控件可以做成全局組件的形式。

  • 看看效果

擴展列表的使用方法

首先還是依據(jù) json 渲染列表,然后根據(jù)需要設(shè)置插槽即可,設(shè)置插槽后會替換默認(rèn)的列。

  • template
  可以使用 slot 自定義擴展列 <br>
  <!--表單控件-->
  <nf-grid
    v-grid-drag="gridMeta"
    v-bind="gridMeta"
    :dataList="dataList"
    :selection="selection"
    size="small"
  >
    <!--普通字段,用字段名作為插槽的名稱-->
    <template #text="scope">
      <div style="display: flex; align-items: center">
        <el-icon><timer /></el-icon>
        <span style="margin-left: 10px">擴展:{{ scope.row.text }}</span>
      </div>
    </template>
    <!--普通字段-->
    <template #week="scope">
      <span style="margin-left: 10px">{{ scope.row.week.replace('-w','年 第') + '周' }}</span>
    </template>
    <!--操作按鈕-->
    <template #option="scope">
      <el-button size="small" @click="handleEdit(scope.$index, scope.row)">修改</el-button>
      <el-button
        size="small"
        type="danger"
        @click="handleDelete(scope.$index, scope.row)">刪除</el-button>
    </template>
  </nf-grid>

通過 slot 擴展列,可以按照 Table-column 的匿名插槽的方式進行設(shè)置。
列的先后順序還是由 colOrder 控制,和插槽的先后順序無關(guān)。

  • 代碼部分
  import { defineComponent, reactive } from 'vue'
  // 使用 圖標(biāo)
  import { Timer } from '@element-plus/icons-vue'
  import { nfGridSlot, createDataList } from '../../../../lib-elp/main'
  import _gridMeta from '../../grid/grid.json'
  import _formMeta from '../../form/form.json'

  import { EAlign } from '../../../../lib/types/enum'
  import type { IGridSelection, IGridItem } from '../../../../lib/types/50-grid'
 
  export default defineComponent({
    name: 'nf-elp-grid-slot-page',
    components: {
      Timer,
      nfGrid: nfGridSlot
    },
    props: {
      moduleID: { // 模塊ID
        type: [Number, String],
        default: 1 
      }
    },
    setup(props) {
      const gridMeta = reactive(_gridMeta)

      // 設(shè)置列的先后順序和是否顯示
      gridMeta.colOrder = [90, 100, 101, 102, 105, 113, 115, 116, 120,121,150, 2000]

      // 設(shè)置一個操作按鈕列
      const optionCol: IGridItem = {
        id: 2000,
        colName: "option",
        label: "操作",
        width: 180,
        fixed: EAlign.right,
        align: EAlign.center, // 使用枚舉
        headerAlign: EAlign.center
      }

      gridMeta.itemMeta['2000'] = optionCol // 設(shè)置操作列,也可以直接在json文件里設(shè)置。
      const dataList = reactive(_dataList)

      const handleEdit = (index: number, row: any) => {
        console.log(index, row)
      }
      const handleDelete = (index: number, row: any) => {
        console.log(index, row)
      }

      return {
        handleEdit,
        handleDelete,
        dataList,
        gridMeta
      }
    }
  })

使用字段名稱作為插槽的名稱,可以把任意字段變成插槽的形式。

如果要添加操作按鈕這類的列,可以給 itemMeta 添加對應(yīng)的列屬性。

  • 看看效果:

管理 json

其實,前面介紹的那些大家可能都會想到,也許早就實踐過了,然后發(fā)現(xiàn)雖然看著挺好,但是其實沒有解決根本問題!只是把 template 里的問題轉(zhuǎn)移到 json 里面。

雖然不需要設(shè)置模板,但是需要設(shè)置 json,還不是一樣,有啥本質(zhì)區(qū)別嗎?

其實不一樣的,管理 json 的難度明顯比管理模板要簡單得多。

比如我們可以做一個維護 json 的小工具:

  • 首先從數(shù)據(jù)庫文檔生成基礎(chǔ)的 json(毛坯房);
  • 然后使用可視化+拖拽的方式設(shè)置格子細節(jié)(精裝修)。

這樣就可以很方便的維護 json 了。具體實現(xiàn)方式,將在下一篇再介紹。

源碼

nf-ui-controller-UI庫的二次封裝的共用 JavaScript 函數(shù): 對UI庫做二次封裝的純JavaScript函數(shù),支持更多的UI庫的時候便于復(fù)用。

nf-ui-elementPlus-基于 element-plus 的二次開發(fā): 封裝UI庫(elementPlus),實現(xiàn)更簡潔的使用方式。

熱門課程推薦

熱門資訊

請綁定手機號

x

同學(xué)您好!

您已成功報名0元試學(xué)活動,老師會在第一時間與您取得聯(lián)系,請保持電話暢通!
確定