我对 Element 的 Table 做了封装

我对 Element 的 Table 做了封装

背景

ElementUI 是一个优秀的组件库,但其 Table 组件的使用方式总让我感觉有些麻烦,我们看下官方文档的示例:

<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>
复制代码

开发者需要在el-table 组件中用 el-table-column 注册想要展示的列,试想一下如果表格有很多列,则需要在 template 中书写大量的 el-table-column , 这无疑会增加后续的维护成本。而社区中其他组件库的表格,通过一个 columns 数组就可以渲染出想要的列,我们看下 iView 的官方示例:

<template>
    <Table :columns="columns" :data="data"></Table>
</template>
<script>
  export default {
    data () {
      return {
        columns: [
          {
            title: 'Name',
            key: 'name'
          },
          {
            title: 'Age',
            key: 'age'
          },
          {
            title: 'Address',
            key: 'address'
          }
        ],
				// ...
      }
    }
  }
</script>
复制代码

此外,因为我们的管理后台项目中存在大量的列表型页面,此类页面的结构大都相同,所有我想在 Table 的基础上更进一步,于是 TableView 组件应运而生。

TableView

TableView 是一个以 Table 为主要内容的页面容器,例如管理后台项目里的各种列表。这类页面一般都包含 搜索表格页脚工具栏表格自定义 几个部分,页面特征明显,可复用性高。TableView 允许你传入一个 columns 数组即可渲染表格中所有的列,每一列还支持通过 render 函数或插槽自定义。此外,它还内置了分页逻辑,并允许用户自定义展示哪些列,但搜索表单部分还需要使用者自己完成,并通过插槽嵌入 TableView

TableView 结构如下图:

tableView-structure.png

internals 为组件内置的功能,包括 Table 部分的列表渲染,footer 部分的分页,还有 customer 部分的列表自定义(自定义展示哪些列)。

slots 插槽当前包含:

  • filter

    页面筛选器,嵌入搜索表单

  • tabBar

    有些页面顶部需要 tab 切换,例如订单管理模块下的待审列表,其又细分为 “待初审”,“初审退回” 等状态。

  • toolBar

    工具栏部分,可在此出嵌入一些按钮,如:导出,新增。

使用

基本用法

tableView-example.png

图中红色部分即为 TableView, 使用者传入一个 columns 数组即可渲染出表格,代码如下:

<template>
  <table-view
    :columns="columns"
    get-list-method="getDataList"
  >
    <template #filter="{ search }">
      <order-filter
        @search="search($event)"
        @reset="search($event)"
      />
    </template>

    <template #toolBar>
      <el-button
        type="primary"
        size="small"
      >导出</el-button>
    </template>
  </table-view>
</template>

<script>
export default {
  // ...
  data() {
    return {
      columns: [
        {
          label: 'Name',
          prop: 'name',
        },
        {
          label: 'Age',
          prop: 'age'
        },
        {
          label: 'Address',
          prop: 'address'
        }
      ]
    };
  },

  methods: {
    async getDataList(params) {
      const res = await Api.getList(params)
      return {
        listData: res.list,
        total: res.total,
        page: res.page
      }
    }
  }
};
</script>
复制代码

描述每一列的对象(column 对象)的完整属性如下, 你可以灵活的控制每一列的展示

{
  // required
  label: '姓名',

  // required
  prop: 'name',

  // ElTableColumn 的属性
  elProps: {
    fixed: true,
  },
  
  // 是否展示
  // 组件prop `useColumnCustomer` 为 true 时生效
  // show 为 false 的列隐藏
  show: true,
  
  // 可通过 render 函数自定义每列展示的内容
  // row: 行数据
  // col: 列数据
  // rowIdx: 行索引 (从0开始)
  // colIdx: 列索引 (从0开始)
  render(h, { row, col, rowIdx, colIdx }) {
    return h(
      'div', 
      { /* ... */ },
      `${row.name}`
    )
  }
}
复制代码

如何自定义列?

TableView 支持通过 render 函数插槽 两种方式自定义列

注意:render 优先级高于插槽

1. render函数

给需要自定义的列设置一个 render 函数, 你可以通过 render 函数渲染想要的内容。如果你自定义的内容比较复杂,你可以像操作列那样,封装一个组件传给渲染函数。

import OperationWidget from './OperationWidget.vue'

export default {
  // ...
  data() {
    return {
      columns: [
        {
          label: '姓名',
          name: 'prop',
          render(h, { row, col, rowIdx, colIdx }) {
            return h(
              'div', 
              { /* ... */ },
              `${row.name}`
            )
          }
        },
        {
          label: '操作',
          prop: 'operation',
          render(h, { row }) {
            return h(OperationWidget, {
              props: {
                orderInfo: row
              }
            })
          }
        }
      ];
    }
  }
}
复制代码

2. 插槽

TableView 允许你通过具名插槽自定义列,插槽名为列的 prop

<template>
  <table-view
    :columns="columns"
    :get-list-method="getListMethod">
    <!-- 'name' 插槽会自定义 prop 为 'name' 的列 -->
    <template #name="{ row }">
      <!-- slot what you want -->
      <div>{{ row.name }}</div>
    </template>
  </table-view>
</template>
复制代码

如何请求数据?

TableView 要求使用者在 getListMethod 里调用接口并回填数据, getListMethod有两种写法:

  1. 异步写法

第一种是写一个返回 Promise 的函数, Promise 需 resolve 接口返回的数据,就像这样:

async getDataList(params) {
  const res = await Api.getList(params)
  return {
    listData: res.list, // 表格数据
    total: res.total,   // 总数
    page: res.page      // 当前页数
  }
}
复制代码
  1. 回调写法

TableView 内部在调用 getListMethod 的时候会传两个参数,第一个是请求参数,第二个则是一个回调函数,用于设置数据, 所以 getListMethod 也可使用如下写法:

getDataList(params, callback) {
  Api
	.getList(params)
	.then(res => {
		callback({
	    listData: res.list, // 表格数据
	    total: res.total,   // 总数
	    page: res.page      // 当前页数
	  })
	) 
}
复制代码

如何搜索?

TableView 需要使用者自己整理搜索条件,然后手动调用内部方法 search,如图:

tableView-filter.png

有两种方式调用 search

1. 通过作用域插槽

<table-view
  :columns="columns"
  get-list-method="getDataList"
>
  <template #filter="{ search }">
    <order-filter
      @search="search($event)"
      @reset="search($event)"
    />
  </template>
</table-view>
复制代码

2. 通过 ref

<template>
	<table-view
	  ref="tableView"
	  :columns="columns"
	  get-list-method="getDataList"
	>
	  <template #filter>
	    <order-filter
	      @search="search($event)"
	      @reset="search($event)"
	    />
	  </template>
	</table-view>
</template>

<script>
export default {
  // ...
  methods: {
    search(params) {
      this.$refs.tableView.search(params)
    }
  }
}
</script>
复制代码

使用内置的自定义列表功能

TableView 内置了自定义列的组件,支持用户勾选想展示的列,隐藏多余的列。

想要使用此功能,需要设置 useColumnCustomertrue, 同时给组件传递 columnCustomMethod 方法。你需要通过 columnCustomMethod 更新 columns, 把自定义展示的列的 show 设为 true, 其他列的 show 设为 false

<table-view
  :columns="columns"
  use-column-customer
  :column-custom-method="columnCustomMethod"
  get-list-method="getDataList"
>
  <!-- ... -->
</table-view>
复制代码
export default {
  // ...
  methods: {
    /**
     * 处理列表自定义
     */
    columnCustomMethod(columnProps) {
      this.columns = this.columns.map(col => ({
        ...col,
        show: columnProps.includes(col.prop)
      }))
      // ...
    }
  }
}
复制代码

当然你还可以更进一步,在 columnCustomMethod 里保存用户自定义的数据,下次渲染列表的时候根据保存的数据把 columns 对应的列的 show 设为 true

源码

TableView 的介绍到此为止,如果你感兴趣的话,请前往 GitHub 查看源码和完整文档。求建议求 star 🌟。 此外,我把 Table 封装为独立的组件,如果你只想使用 Table 部分,请直接查看 src/Table.vue 文件

GitHub - JackLiR8/table-view

分类:
前端
标签: