深耕系列之基于element-ui的表格页面组件化

·  阅读 1910

前段时间,有后端开发人员找到我,让帮忙写后台管理页面,我司后台管理页面是用element-ui组件库,用过element-ui组件库的同学都知道,element-ui封装了很多常用的组件,特别是el-table、el-form和el-dialog组件。 后台项目的页面需求一般都是表格的查询,新增,编辑,分页等,按理说这都是一些简单的需求,但是我在查阅旧代码时,发现很多页面代码动辄数百行代码,甚至上千行代码,显得很冗余,我裂开了。 经过分析发现

  • 没有拆分为多个组件,开发人员习惯把所有代码放在一个vue文件
  • 代码里存在很多从别处copy过来的无效代码
  • 不同页面的展示风格不一致
  • 相同的功能在不同页面中都各自实现了一遍

那么,能否封装出一个基于element-ui的组件库,开发人员只需要配置相关参数和处理接口请求就可以生成一个整洁的页面呢?

一、需求分析

我们先来看一下常见后台页面的展示:

1.png

可以看出,后台页面主要有菜单栏、搜索栏、table栏和分页栏。详细分析后,这个页面大概有以下功能:

  1. 切换菜单栏展示不同页面。
  2. 可以根据搜索栏的内容来过滤数据。
  3. 点击提示icon可以展示提示信息。
  4. 可以自动分页。
  5. 页面的内容全部展示在一屏,不出现上下滚动条。
  6. 搜索栏的筛选条件可以同步到url上。
  7. 点击search按钮自动展示loading效果,搜索结束后自动关闭loading效果。

这些功能我们都可以用element-ui组件来实现,然后封装成一个页面级组件。

如果封装成一个页面级组件,那么这个组件如何才能更好的被复用?

想到这,我开始思考我到底想要做一个什么样的组件,是想要所有页面都能复用这个组件吗?是希望写特别简短的代码吗?

实际上,功能越复杂的组件,其复用性就越差,这是一个平衡性的问题,基于此,我确定了我想要做的组件样子:

  1. 是针对后台管理系统中常见的表格类页面,并非要针对所有页面。
  2. 组件要易于被复用,易于扩展,在一定程度上可自定义。
  3. 基于element-ui的二次开发。
  4. 不封装axios到组件内,因为对接口的请求和响应数据处理变化太多。

基于此,我设计了 backoffice-ui组件库,可看 backoffice-ui

二、快速使用

安装npm包

npm install backoffice-ui
复制代码

项目引入

import Vue from 'vue'
import BackofficeUI from 'backoffice-ui'

Vue.use(BackofficeUI)
复制代码

页面组件中使用

1. 如果有菜单栏,使用bo-menu

<template>
  <div>
    <bo-menu :menus="menus">
      <template #statistics>
        <statistics />
      </template>
      <template #log>
        <log />
      </template>
    </bo-menu>
  </div>
</template>

<script>
import statistics from './statistics.vue'
import log from './log.vue'

export default {
  components: {
    statistics,
    log
  },
  data() {
    return {
      menus: [
        {
          index: 'statistics',
          label: 'Statistics'
        },
        {
          index: 'log',
          label: 'Log'
        }
      ]
    }
  }
}
</script>
复制代码

2. 使用bo-page来生成表格

// log.vue文件

<template>
  <bo-page
    :form-options="formOptions"
    :columns="columns"
    :table-options="tableOptions"
    @search="handleSearch($event)"
    @excel="handleSearch($event, true)"
  />
</template>

<script>
export default {
  data() {
    return {
      // 定义搜索栏
      formOptions: {
        forms: [
          { prop: 'date', label: 'Date:', itemType: 'daterange', dayRange: 1 },
          { prop: 'uid', label: 'Uid:', urlSync: true }
        ],
        autoSearch: true   // 进入页面是否自动搜索
      },
      // 定义table栏
      columns: [
        { prop: 'userID', label: 'User ID' },
        { prop: 'nickname', label: 'Nickname' },
        { prop: 'type', label: 'Type' },
        { prop: 'amount', label: 'Amount' },
        { prop: 'balance', label: 'Balance' },
        { prop: 'note', label: 'Note' },
        { prop: 'date', label: 'Date' }
      ],
      // table栏和分页栏的数据
      tableOptions: {
        data: [],
        paginationTotals: 0
      }
    }
  },
  methods: {
    async handleSearch(filter, excel) {
      // 获取数据逻辑
      const { data = [], total = 0 } = (await this.$requestPost('/flows/ReadFlowDiamonds', filter)).data

      if (excel) {
        // 导出逻辑
      } else {
	// 更新数据
        this.tableOptions = { data, paginationTotals: total }
      }
    }
  }
}
</script>

复制代码

截图如下:

2.png

页面效果如上所示,那我们该如何去设计backoffice-ui组件库呢?

三、Backoffice-ui组件库设计和实现

1. 文件夹结构

image.png

组件库的组成如下:

  1. storybook 是用来编写文档
  2. packages 保存着该组件库所拥有的组件
  3. src 保存着测试例子
  4. changelog.md 是日志变更

核心在于packages文件夹,里面的组件的功能是什么呢?

2. 各组件功能

主要有以下组件

  1. bo-page组件,基于其他bo组件二次开发(核心)
    • 由其他bo组件派生,配置选项可参考其他bo组件
    • 实现了一屏展示所有页面内容,根据浏览器高度自动确定bo-table高度,不出现上下滚动条
    • 实现点击search按钮,自动返回筛选参数和展示loading效果,更改数据后自动关闭loading效果
    • 实现自动分页功能
    • 可根据table数据,配置x轴和y轴,自动展示图表
    • 可展示多个table
  2. bo-dialog组件,基于其他bo组件二次开发(核心)
    • 封装了el-dialog和其他bo组件
    • 支持插槽,提供render,html,slot等拓展
    • 支持配置add和type,用来区分新增还是编辑功能
    • 支持配置input,select,multSelect,date,daterange等
  3. bo-select组件
    • 封装了el-select,实现多选
  4. bo-menu组件
    • 封装了el-menu,可根据url自动切换,如查询参数tab=log,则自动切换到log选项
  5. bo-pagination组件
    • 封装了el-pagination,可自动分页,分页后自动滚到顶部
  6. bo-search组件
    • 封装了el-form,可实现自动搜索,插入导出按钮,提示icon,同步查询参数到url等功能
    • 支持配置input,select,multSelect,date,daterange等
  7. bo-table组件
    • 封装了el-table,可实现多级表头,求和或平均值,千分位等功能
    • 支持插槽,提供render,html,slot等拓展
  8. bo-currency-input组件
    • 封装了el-input,自动将输入格式转成千分位
  9. bo-chart组件
    • 封装了vue-charts组件,提供折线图,柱状图,饼图等等

3. 常见功能介绍

功能1: bo-search的栏位和url同步

有时候,我们希望url中的查询参数和筛选栏的条件可以同步,为此设计了urlSync,如果urlSync: true,则url查询参数和筛选条件同步,例子如下:

image.png

页面展示:

http://10.100.0.251:9527/economic/diamonds?tab=log&uid=123
复制代码

image.png

实现思路:

  • 当页面刷新时,筛选条件的默认值会对应url的查询参数;当点击search按钮时,会把筛选条件同步到url查询参数。

  • bo-menu组件也实现urlSync,会默认查询变量为tab,如tab=log就切换到log。当bo-search组件的筛选变量为tab,会报错误提示。

  • 由于vue项目一般都会用vue-router,会分hash模式和history模式。为了便于实现,同步逻辑采用vue-router的方法,backoffice-ui组件库依赖于vue-router组件。

    image.png

由于是采用this.$router.replace进行同步参数,如果筛选栏是多选框,那么要慎重用urlSync,因为url在浏览器是有长度限制的。

功能2:bo-table的拓展

有些需求要对表格的字段进行处理,比如数字的千分位,编辑和删除按钮等等。为了bo-table可以更好的拓展,增加4种类型,如下:

  • filter,可以对数据进行过滤,backoffice-ui自带千分位过滤,后续会不断增加常见功能。
  • render,对数据进行初步过滤。
  • html,对数据转化成带style样式的内容,用v-html实现。
  • slot,定义插槽,可实现自定义组件。

代码例子如下:

image.png

image.png

展示如下:

image.png

bo-dialog同样也实现了插槽功能,便于自定义。

功能3:bo-table的多级表头

有些需求的table的表头是多级表头,如下:

image.png

代码例子如下:

image.png

实现思路:

  1. bo-table使用递归组件tableColumn来实现多级表头
  2. 递归组件tableColumn中实现原来bo-table的功能

功能4:bo-page自动处理loading

一般来说,用户点击serach按钮,页面先展示loading动画,然后通过筛选参数去调接口获取数据,获取数据后更新table并关闭loading动画。而bo-page不在需要手动展示loading动画。

代码例子如下:

image.png

image.png

实现思路:

  1. 用户点击search按钮时,展示loading效果并返回筛选条件,触发search事件
  2. 用户拿到筛选条件后,通过接口获取数据,然后更新this.tableOptions.data数据
  3. bo-page组件会监听数据,判断shi.tableOption.data数据有变化就关闭loading动画
  4. 如果用户在调用接口报错时,通过vuex通知bo-page组件去关闭loading动画,由于backoffice-ui不依赖vuex,项目在引入backoffice-ui组件时,需要传入loading在vuex配置的位置

image.png

image.png

功能5:bo-table和折线图、柱状图等图表关联起来

有些表格用折线图等图形展示更直观,为了支持图表展示,设计了chart属性。 代码如下:

<template>
  <bo-page
    :formOptions="formOptions"
    :columns="columns"
    :tableOptions="tableOptions"
    :tabs="tabs"
    @search="search"
    @excel="excel"
  >
  </bo-page>
</template>
<script>
export default {
  data() {
    return {
      "formOptions": {
        "forms": []
      },
      "columns": [
	{ "prop": "time", "label": "Time" },
        { "prop": "prop1", "label": "Label1" },
        { "prop": "prop2", "label": "Label2" }
      ],
      "tableOptions": {
        "chart": {
          "show": true,
          "type": "line",
          "labelProp": "time",
          "dataProps": []
        },
        "data": [
	  { "time": "10:00", "prop1": 1, "prop2": 2 },
          { "time": "11:00", "prop1": 10, "prop2": 20 },
          { "time": "12:00", "prop1": 11, "prop2": 12 },
          { "time": "13:00", "prop1": 15, "prop2": 18 }
        ]
      }
    };
  },
}
</script>
复制代码

展示如下:

image.png

核心在于this.tableOptions.chart属性,可以配置是否展示,图表类型,x和y轴。

四、总结归纳

这个基于element-ui开发的组件库还有许多功能,就不一一展示了。该组件库也应用到我司的项目中,后续会不断完善,更多功能和细节请查看 backoffice-ui。教程文档请查看 文档 。 如果觉得对你有帮助,不要吝啬点个赞哈。也欢迎大家fork该项目并提交pull request。

大家在开发后台管理页面时,是否还遇到其他问题?也欢迎到评论区探讨。

分类:
前端
标签:
收藏成功!
已添加到「」, 点击更改