【轮子】Element UI 的Form, Table, Pagination组件封装来一波

7,794 阅读8分钟
原文链接: mp.weixin.qq.com

造轮子的目的,是为了更爽的开发。当然,大家都在说,不要重复造轮子,只是我没有找到同样的轮子,才自己造了一个。也看到有人封装过 Element 的 Table,只是感觉封装的太浅,不够深入。下面说的这个,可能也是你需要的。

全文共 2388 字,读完需 6 分钟。

同步发表于知乎专栏:前端微志

惯例,开始之前,贴个Github地址,求 star😂。点击 阅读原文 去 GitHub 瞅瞅。

https://github.com/zollero/el-search-table-pagination

用 Vue 做前端开发的同学,肯定都听说过 Element UI (下文中称为 Element)这个由 饿了么前端团队 开发的基于 Vue 的 UI 组件库。

而用 Element 做的最多的就是 Table,且这个 Table 需要支持分页 和 搜索查询,且还会有一些操作按钮,用来处理数据。

前奏

系统中有很多页面都用到了 Element 的 Form, Table, Pagination 组件。当这种页面多了之后,就会出现很多重复代码,使得业务代码的占比不高,需要花更多的时候去维护非业务代码,效率不高,也有一些风险。

写多了之后,我决定封装一个通用组件,可以让我只用关注业务代码就可以。

一般情况下,我们使用 Element 的 Table,Pagination 组件 写一个简单的页面,会像下面这样。

(查看大图更清晰)

可以看出,要写这样一个页面,有一些东西需要处理,如:默认加载数据,分页切换等操作,都是需要单独处理。一般,在 Table 上面,还有一个搜索框,里面有几个搜索条件的输入框用来辅助搜索展示数据。这些操作步骤,是重复性的,再新建一个页面,都要再写一遍。

这样一个没效率的事情,怎么能忍?所以 el-search-table-pagination 应运而生,帮助开发者更好地用 Element 编写包含 Form,Table 和 Pagination 组件的页面。

还拿上图中的功能为例,用 el-search-table-pagination 重写之后,是下面这样的。

(查看大图更清晰)

重构之后,代码简洁很多,将通用代码抽离,开发者只需要关注业务代码即可,不用再维护很多重复代码。

特性

上面例子中说了 el-search-table-pagination 组件的简单使用,为了让它保持一定的通用性,做了一些封装,有一些细节你可能需要知道。

  • 默认使用 axios 查询远程数据,当然你也可以配置一个封装之后的 axios(你可能会设置一些 interceptor)

  • 最大化地像可配置化迈进,让你尽可能少的写 html,最大化地支持 Element 中的特性(持续更新)

  • 同样可以配置搜索框中的搜索条件,如:输入框,下拉框,日期选择框、日期范围选择框等(后续会支持更多form item)

  • 除了支持远程数据的分页查询展示,还支持本地数据的分页及查询过滤

  • CSS 样式使用 Element 中的样式,如果需要修改默认样式,按原来的方式做就行

  • table-column 中如果需要转换结构,可以使用 slot 来嵌套

使用

使用方法跟 Element 类似。

如果你想直接用,没有自己封装 axios,可以这样:

 import Vue from 'vue'
import ElSearchTablePagination from 'el-search-table-pagination'
 
// Default use axios as HTTP tool
Vue.use(ElSearchTablePagination)

如果你有自己封装 axios,可以在使用的时候,默认传入,这样将使用你传入的 axios 实例调用远程接口:

 import Vue from 'vue'
import ElSearchTablePagination from 'el-search-table-pagination'
// 你自己封装了 axios
import axios from './utils/axios'
Vue.use(ElSearchTablePagination, {
  axios
})

当然,你也可以使用 CDN,在 html 文件中使用 script 标签来引用。

在 CODEPEN 上建了两个 DEMO 分别展示 本地数据 和 远程数据。DEMO 地址如下:

本地数据:

  https://codepen.io/zollero/pen/wPRqYX

远程数据:

 https://codepen.io/zollero/pen/xPmXBp

中文文档在此,欢迎打醒:

https://github.com/zollero/el-search-table-pagination/blob/HEAD/docs/zh_CN.md

注意事项

转换 table-column 内容的方式

很多时候,接口中字段的值,需要做转换才能展示,在 columns 中 column 的属性,提供了几种方式来帮你转换。

一、filter

如果你只需要使用 filter 转换这个字段的值,把 filter 的名称赋给filter就可以了,注意:只有注册在Vue 全局的 filter才有效

 // 使用 filter 属性转换内容
const columns = [
  {
    prop: 'updateTime',
    label: '更新时间',
    width: 110,
    filter: 'formatDate'
  },
  ...
]

上面用到的 filter 需要注册在 Vue 全局内才有效。

 // 需要提前注册好这个 filter
Vue.filter('formatDate', (value) => {
  if (!value) return '';
  let d = new Date(value);
  return d.getFullYear() + '-' 
         + (d.getMonth() + 1) + '-' 
         + d.getDate()
})

二、render

如果你想通过一个函数来转换一下,就把函数设置给 render 属性吧,记得将最终的值 return 出来。

 // 使用 render 属性转换内容
const columns = [
  {
    prop: 'price',
    label: '价格
    minWidth: 130,
    render: row => `${row.price} 元`
  },
  ...
]

三、slotName

如果内容需要一段 HTML 重新填充到 table 内,这种方式最直观。首先在 el-search-table-pagination 标签内定义一个 slot,然后将 slot 的值赋给 slotName 即可。

 // 使用 slotName 属性来转换内容
const columns = [
  {
    label: '预览',
    prop: 'url', // 此时为选填
    width: 380,
    slotName: 'preview-column'
  },
  ...
]

上面用到的 slot: preview-column 需要在 el-search-table-pagination 标签内声明,如下:

 // 声明 slot,这种方式支持负责内容渲染
// 代码中 slot-scope 属性是 Vue v2.5.x 之后的属性
// 如果你的 Vue 版本低于 v2.5.x,请使用 slot
<el-search-table-pagination
  :columns="columns"
  ... >
  <template slot="preview-column" 
    slot-scope="scope">
    <img width="350px" 
      :src="scope.row.url" />
  </template>
</el-search-table-pagination>

操作列

很多场景下,都会需要在 Table 右侧添加一个 操作列,操作列里需要一些按钮,用来处理数据交互等。

这时候,你可以在 el-search-table-pagination 标签下使用 slot: append,可以在 Table 右侧添加一个 操作列。示例如下:

 <el-search-table-pagination
  :columns="columns"
  ... >
  <el-table-column slot="append">
    <template slot-scope="scope">
      <div>
        <el-button type="success">
          通过
        </el-button>
        <el-button type="danger">
          退回
        </el-button>
      </div>
    </template>
  </el-table-column>
</el-search-table-pagination>

Form 的配置化

插件提供了对 Form 表单的可配置实现,只需要提供 form-options 属性即可,其中 formOptions.forms 属性是一个数组,用来配置多个 form item。

forms 定义的 prop 属性的值,是会被传给后端接口的参数名。当然,传给后端接口的时候,还会带上分页参数。

首先需要注意的是属性:form.itemType

itemType 表示 from item 的类型,目前支持四种:input,select,date 和 daterange,且默认是 input。对应的是 Element 中的输入框,下拉框,日期选择框,日期范围选择框。

一、input

输入框比较简单,只需要设置好一下几个字段即可:

 const forms = [
  {
    prop: 'url',
    label: 'url地址',
    size: 'small', // 选填
    itemType: 'input'
  },
  ...
]

二、select

下拉框相对复杂点,除了要配置 input 的那些参数,还有一些参数需要注意。

由于,下拉框的下拉选项的值可能是代码里写死的,也可能是从接口中获取的。所以,针对这两种提供了两种写法。

 // 下拉选项的值是代码里写死的
const forms = [
  {
    prop: 'status',
    label: '状态',
    size: 'small',
    itemType: 'select',
    options: [{
      value: '',
      label: '全部'
    }, {
      value: '1',
      label: '通过'
    }, {
      value: '2',
      label: '退回'
    }]
  },
  ...
]
// 下拉选项的值有部分是代码写死的
// 有部分是从接口中获取的
const forms = [
  {
    prop: 'name',
    label: '名称',
    size: 'small',
    itemType: 'select',
    options: [{
      value: '',
      label: '全部'
    }],
    // fetch 和 url 可任选一项
    // selectUrl: 'http://x.com/a'
    selectFetch: axios.get('http://x.com/a')
  },
  ...
]

三、date

这种类型也比较简单,跟 input 非常类似。

 const forms = [
  {
    prop: 'date',
    label: '日期',
    size: 'small',
    editable: false,
    itemType: 'date',
    placeholder: '请选择日期'
  },
  ...
]

四、daterange

daterange 是针对那种选择日期范围的情况,因为经常遇到接口中要求传 开始日期 和 结束日期 两个字段,daterange 就是为这种场景而生的。

与前面几种类型不同的是,daterange 的 prop 属性需要传递一个数组,数组的是分别是 开始日期 和 结束日期 的字段值。

 const forms = [
  {
    prop: ['dateStart', 'dateEnd'],
    label: '日期范围',
    size: 'small',
    editable: false,
    itemType: 'daterange',
    placeholder: '请选择日期范围'
  },
  ...
]

目前,只支持这四种类型,后续会添加更多类型支持。

结尾

插件已经发布到 npm 上了,大家可以直接下载使用,或者去 GitHub 上扔个 PR 或 ISSUE,不管怎样,欢迎来个star😂。

本文只是简单介绍了插件的功能,更多功能,还请参考 文档。

npm 包地址:

https://www.npmjs.com/package/el-search-table-pagination