Element實現動態表格的示例代碼

【代碼背景】

有這樣一個業務需求場景,有大概十幾張表歸屬於某個類別,用戶希望在同一個頁面,通過選擇不同的查詢指標展示不同的表格,這些表的表頭樣式類似但是又不完全相同,怎麼做呢?

到目前為止所有基於Element UI的表格樣式都是直接在頁面寫死的,像官方這樣:

<el-table :data="tableData" style="width: 100%">
    <el-table-column prop="date" label="日期" width="180"></el-table-column>
    <el-table-column prop="name" label="姓名" width="180"></el-table-column>
    <el-table-column prop="address" label="地址"></el-table-column>
</el-table>

要解決上述問題,最簡單暴力的方式是為每個表寫一個單獨組件,然後通過select框觸發事件切換不同組件路由渲染頁面,當然這種方式很笨,也不符合代碼復用的基本原則,所以為瞭偷懶,為瞭堅守代碼復用的基本原則,開始思考有沒有更好的方式來解決這個問題。

仔細觀察這個<el-table>,表格數據是通過:data綁定的,表格頭部數據則是通過<el-table-column>標簽展示的,表頭數據是不是也可以通過某種傳參的方式結合v-for來渲染<el-table-column>的具體數據呢?在度娘的幫助下,果然有大佬已經這樣做瞭,實現瞭動態表格,參考鏈接掛在最底下瞭哦,在此特別感謝免費分享知識的大佬們,知識無價,學無止境。

現將本項目的具體實現代碼記錄如下,完善瞭一些代碼的註解,嘗試幫助理解。

【代碼實現】

#1# -> 代碼復用的基礎是你需要一個可復用的組件

在/components/Table文件夾下新建兩個組件

DynamicTable.vue

<template>
  <!-- 動態展示表格 -->
  <el-table :data="tableData" border stripe :height="height" @row-click="handleRowClick">
    <!-- v-for 循環取表頭數據 -->
    <template v-for="item in tableHeader">
      <table-column v-if="item.children && item.children.length" :key="item.id" :column-header="item" />
      <el-table-column v-else :key="item.id" :label="item.label" :prop="item.prop" align="center" />
    </template>
  </el-table>
</template>
<script>
  import TableColumn from '@/components/Table/TableColumn'
 
  export default {
    name: 'DynamicTable',
    components: {
      TableColumn
    },
    props: {
      // 表格的數據
      tableData: {
        type: Array,
        required: true
      },
      // 多級表頭的數據
      tableHeader: {
        type: Array,
        required: true
      },
      // 表格的高度
      height: {
        type: String,
        default: '300'
      }
    },
    methods: {
      // 行點擊事件
      handleRowClick (row, column, event) {
        // console.log(row)
        // console.log(column)
        // console.log(event)
        // 通知調用父組件的row-click事件
        // row作為參數傳遞過去
        this.$emit('row-click', row)
      }
    }
  }
</script>

TableColumn.vue

<template>
  <el-table-column
    :label="columnHeader.label"
    :prop="columnHeader.label"
    align="center"
  >
    <!--columnHeader對應:column-header-->
    <template v-for="item in columnHeader.children">
      <tableColumn
        v-if="item.children && item.children.length"
        :key="item.id"
        :column-header="item"
      />
      <el-table-column
        v-else
        :key="item.name"
        :label="item.label"
        :prop="item.prop"
        align="center"
      />
    </template>
  </el-table-column>
</template>
 
<script>
  export default {
    name: 'TableColumn',
    props: {
      columnHeader: {
        type: Object,
        required: true
      }
    }
  }
</script>
 
<style scoped>
 
</style>

幾點重要說明:

(1)表格頭部的傳參主要分為兩類:帶children節點和不帶children節點的,如下圖所示

請註意children節點是為瞭完成復雜表頭的渲染,例如上面這個示例最終的表頭渲染樣式如下:

那麼問題來瞭,<el-table-column>是<el-table>的標簽,那這個<table-column>是個啥?

(2)DynamicTable.vue調用TableColumn.vue組件

DynamicTable.vue通過:column-header給TableColumn.vue傳遞帶children子節點的表頭信息,TableColumn.vue接收到這個節點信息後,主要做瞭以下兩件事情:

第一:通過<el-table-column>渲染瞭一個label標簽

第二:繼續判斷該節點是否存在children子節點

=> 如果存在children節點,繼續通過<table-column>進行渲染,繼續把這個子節點傳給TableColumn.vue組件,重復上述步驟

=> 如果不存在children節點,表示這是一個終止節點,通過<el-table-column>渲染結束

#2# -> 在展示頁面使用動態表格組件

<template>
  <div class="demo">
    <el-card>
      <!--查詢區域-->
      <el-row :gutter="10">
        <el-col :span="6">
          <div class="grid-content bg-purple">
            <span style="margin-right: 10px">選擇框 -</span>
            <el-select
              v-model="specified_table"
              placeholder="請選擇"
            >
              <el-option
                v-for="item in options"
                :key="item.zb_code"
                :label="item.zb_name"
                :value="item.zb_code"
              />
            </el-select>
          </div>
        </el-col>
        <el-col :span="6">
          <div class="grid-content bg-purple">
            <el-button type="primary" plain @click="handleQueryClick">查 詢</el-button>
          </div>
        </el-col>
      </el-row>
      <!--表格區域-->
      <dynamic-table
        v-if="dynamicTableShow"
        :table-data="tableData"
        :table-header="tableHeaders"
        :height="'550px'"
      />
    </el-card>
  </div>
</template>
<script>
  // 引入組件
  import DynamicTable from '@/components/Table/DynamicTable'
  // 獲取表頭信息
  import { getTableHeader02_1, getTableHeader02_2, getTableHeader02_3, getTableHeader02_4 } from '@/api/table-header'
 
  export default {
    name: 'Index',
    components: { // 組件註冊
      DynamicTable
    },
    data () {
      return {
        // -- 查詢 ----------------------
        options: [
          // { zb_name: '指標名', zb_code: '指標代碼' }
        ],
        specified_table: '', // 指標值
        // -- 表格 ----------------------
        dynamicTableShow: true, // DynamicTable組件重新渲染變量
        // 表頭數據
        tableHeaders: [],
        // 表格數據
        tableData: []
      }
    },
    created () {
      // api-獲取指標的下拉框數據
      getSpecifiedTable().then(res => {
        this.options = res.data
      })
    },
    methods: {
      // 判斷值是否在數組中
      isExistArr (arr, val) {
        return arr.includes(val)
      },
      // 重新渲染表格
      refreshTable (zb_code) {
        // 根據value值獲取label值
        const obj = this.options.find((item) => {
          return item.zb_code === zb_code
        })
        console.log(zb_code)
        console.log(obj.zb_name)
        // 設置dynamicTableShow為false,使得DynamicTable組件重新渲染
        this.dynamicTableShow = false
        // 根據不同指標渲染不同的表頭
        const TBArr01 = ['M01', 'M02', 'M03', 'M05'] // 第1類表
        const TBArr02 = ['M04', 'M07', 'M08', 'M12'] // 第2類表
        const TBArr03 = ['M09', 'M10', 'M11'] // 第3類表
        const TBArr04 = ['M06'] // 第4類表
        if (this.isExistArr(TBArr01, zb_code)) {
          this.tableHeaders = getTableHeader02_1(obj.zb_name) // 渲染表頭樣式1
        }
        if (this.isExistArr(TBArr02, zb_code)) {
          this.tableHeaders = getTableHeader02_2(obj.zb_name) // 渲染表頭樣式2
        }
        if (this.isExistArr(TBArr03, zb_code)) {
          this.tableHeaders = getTableHeader02_3(obj.zb_name) // 渲染表頭樣式3
        }
        if (this.isExistArr(TBArr04, zb_code)) {
          this.tableHeaders = getTableHeader02_4(obj.zb_name) // 渲染表頭樣式4
        }
        // api - 獲取表格數據
        getTableList02(zb_code).then(res => {
          this.tableData = res.data
        })
        // 此處是DOM還沒有更新,此處的代碼是必須的
        this.$nextTick(() => {
          // DOM現在更新瞭
          this.dynamicTableShow = true
        })
      },
      // 點擊[查詢]事件
      handleQueryClick () {
        const zb_code = this.specified_table
        // 校驗查詢條件不能為空
        if (zb_code === '' || zb_code === undefined) {
          this.$message.warning('指標不能為空!')
        } else {
          console.log('zb_code: ' + zb_code)
          // 重新渲染表頭和表格
          this.refreshTable(zb_code)
        }
      }
    }
  }
</script>

使用動態表格組件相對來說比較簡單,唯一需要註意的地方是,渲染表格頭部跟數據時必須需要添加以下代碼,不然頁面無法按照預期完成渲染。

this.$nextTick(() => {
    // DOM現在更新瞭
    this.dynamicTableShow = true
})

關於this.$nextTick()可以參考官網:https://cn.vuejs.org/v2/guide/reactivity.html

#3# -> 如何給動態表格根據需求動態添加序號列/索引列

在Element UI官方例子中,如果需要給table添加一個序號列或者索引列非常簡單,直接在<el-table>裡聲明一個特殊的<el-table-column>即可。

<el-table-column type="index" width="50"></el-table-column>

那如何在動態表格組件裡添加序號列呢?更甚者如果根據需要自行添加或者不添加?

首先我們來改造 DynamicTable.vue

像官方例子一樣,我們先在<el-table>裡也聲明一個<el-table-column>

<el-table-column v-if="isIndex" type="index" width="100" label="序號" align="center" />

註意到這裡有一個v-if綁定瞭一個isIndex值,這個值就是我們需要在父組件進行傳值的關鍵瞭

在props裡聲明isIndex為Boolean類型

 props: {
      // 表格的數據
      tableData: {
        type: Array,
        required: true
      },
      // 多級表頭的數據
      tableHeader: {
        type: Array,
        required: true
      },
      // 表格的高度
      height: {
        type: String,
        default: '300'
      },
      // 是否需要添加序號列
      isIndex: {
        type: Boolean
      }
}

在展示頁面使用組件時通過:is-index傳入指定參數

 <dynamic-table
        v-if="dynamicTableShow"
        :table-data="tableData"
        :table-header="tableHeaders"
        :height="'550px'"
        :is-index="true"
/>

在同頁面表頭需要切換的情況下,上面這種寫法容易在頁面初始化時候單獨顯示一個序號列,就像下面這樣,非常不美觀

我希望序號列可以和其他普通列一樣在表頭渲染的時候同時加載,可以這樣做

<dynamic-table
        v-if="dynamicTableShow"
        :table-data="tableData"
        :table-header="tableHeaders"
        :height="'550px'"
        :is-index="isAddIndex"
/>

將原本的常量“true”修改成一個變量isAddIndex替代,然後在表頭渲染完成的時候將其值修改成true

 this.isAddIndex = true

這樣序號列就能跟其他普通列同時進行渲染瞭。

【參考資料】

https://www.jianshu.com/p/9c4ba833658f

https://www.cnblogs.com/llcdxh/p/9473458.html

到此這篇關於Element實現動態表格的示例代碼的文章就介紹到這瞭,更多相關Element 動態表格內容請搜索WalkonNet以前的文章或繼續瀏覽下面的相關文章希望大傢以後多多支持WalkonNet!

推薦閱讀: