ElementUI表格分页组件封装

1,983 阅读1分钟

前言

模板中写的话,如果业务表格很多,template不够简洁,而且模板列也不能很好的做到复用。所以考虑到使用columns来动态渲染配置列。

  1. columns数组,灵活
  2. template中写法简洁,常规简单表格,就一个标签
  3. 动态列逻辑处理直接编程式处理,代码结构清晰

封装思路

下面都以EleTable来命名封装的Table组件。

1. Table属性

el-table属性保持一致,通过v-bind="$attrs"来绑定,增加columns属性。

<EleTable
  :columns="tableColumns"
  :data="tableData"
  border
>
  <template #action="{ row }">
    <TableExportButton
      :row="row"
      @export-action="handleExportAction"
    ></TableExportButton>
  </template>
</EleTable>

2. 列属性

列属性保持和el-table-column一致,直接通过v-for="item in columns"结合v-bind="item"来绑定数组中的属性,columns配置实例:

export const columns = [
  {
    prop: 'id',
    label: 'ID'
  },
  {
    prop: 'name',
    label: '学校名称'
  },
  {
    prop: 'action',
    slotName: 'action',
    label: '学校名称'
  },
]

这里我们考虑到需要slot的场景,所以在列里增加slotName,组件中通过此属性来判断是否需要渲染slot

<!-- 应用 -->
EleTable
  <template #action="{ row }"></template>

组件中处理:

<template v-if="item.slotName" v-slot:default="scope">
  <!-- 列default slot
    @bind 当前的scope
  -->
  <slot :name="item.slotName" v-bind="scope" />
</template>

3. loading

使用表格的loading实现通用的加载效果,简化应用写法,直接loading接口

<!-- EleTable.vue -->
<el-table
  v-loading="loading"
  element-loading-text="数据正在加载中..."
  element-loading-spinner="el-icon-loading"
>
</el-table>

<!-- use.vue -->
<EleTable
  :columns="tableColumns"
  :data="tableData"
  border
  :loading="loading"
/>

4. 分页

内置分页,可以通过paginate来启用,与el-pagination的属性一致,减少使用学习成本。

<el-pagination
  v-if="paginat"
  :total="total"
  :page-sizes="pageSizes"
  :page-size.sync="scopePagesize"
  @size-change="handlePageSizeChange"
  @current-change="handleCurrentPageChange"
  :current-page.sync="scopePage"
  :layout="layout"
></el-pagination>

使用的时候如下:

 <EleTable
  :columns="tableColumns"
  :data="tableData"
  paginat
  :total.sync="total"
  :page.sync="page"
  :page-size="pageSize"
  :loading="loading"
  border
  @load-data="fetchTableData"
/>

分页数据加载方法如上load-data,传入接口调用方法,在EleTable中,分页的相关事件都会emit一个load-data,携带{ page, pagesize },并会同时update掉外层绑定的page\pageSize

this.$emit('load-data', paginationModel);

后续

实际应用中,不支持嵌套表头,以及表头的slot自定义

头部slot

增加headerSlotName属性

<template
  v-if="item.headerSlotName"
  :slot="item.headerSlotName ? 'header' : null"
  slot-scope="scope"
>
  <!-- 列header slot
    @bind 当前的scope
  -->
  <slot :name="item.headerSlotName" v-bind="scope" />
</template>

嵌套头部

考虑到基本嵌套一层,并在columns的配置单列中,增加nest属性,大致如下:

<el-table-column
  v-if="item.nest"
  :key="customkey ? item[customkey] : index"
  :label="item.label"
  v-bind="item"
>
  <!-- 使用slot模式进行嵌套 -->
  <template v-if="item.nest === 'slot'">
    <!--嵌套slot
      @bind 当前的column
    -->
    <slot :name="item.nestSlotName" v-bind="item" />
  </template>
  <!-- 使用数组嵌套,只能嵌套一层 -->
  <template v-else-if="item.nestColumns && item.nestColumns.length">
    <el-table-column
      v-for="(nestItem, nestIndex) in item.nestColumns"
      :key="nestItem[customkey] || nestIndex"
      :label="nestItem.label"
      v-bind="nestItem"
    >
      <template
        v-if="nestItem.headerSlotName"
        :slot="nestItem.headerSlotName ? 'header' : null"
        slot-scope="scope"
      >
        <!-- 嵌套子列的header slot
          @bind 当前列的scope
        -->
        <slot :name="nestItem.headerSlotName" v-bind="scope" />
      </template>
      <template v-if="nestItem.slotName" v-slot:default="scope">
        <!-- 嵌套子列的内容default slot
          @bind 当前scope
        -->
        <slot :name="nestItem.slotName" v-bind="scope" />
      </template>
    </el-table-column>
  </template>
  <template v-slot:default="scope">
    {{ item.nest }}
    <!-- 嵌套列的default slot
      @bind 当前的scope
    -->
    <slot :name="item.nestSlotName" v-bind="scope" />
  </template>
</el-table-column>

基本上完成了。

感谢阅读,欢迎讨论~