vue2 + Element-ui 二次封装 Table 组件,打造通用业务表格

在 Vue2 项目中,使用 Element-ui 组件库的 Table 表格组件进行业务开发是常见的需求。为了提高开发效率,我们可以对 Table 组件进行二次封装,使其成为一个通用业务表格。本文将详细介绍如何实现这一过程。

一、引言

在业务开发中,表格组件是不可或缺的工具。为了提升开发效率和代码的可维护性,我们对 Element-ui 的 Table 组件进行了深度二次封装,打造了一个功能丰富的通用业务表格组件。该组件不仅具备以下核心特性,还预留了扩展空间,以满足更复杂的业务需求:

  1. 灵活的插槽机制:提供默认插槽和多个自定义插槽,轻松实现功能扩展和个性化内容渲染;
  2. 完善的分页功能:集成分页控件,支持页码和页大小的切换,方便数据管理和浏览;
  3. 树形结构支持:能够展示层级关系的数据,适用于需要树形展示的场景;
  4. 行点击响应:内置行点击事件,方便用户进行行级别的交互操作;
  5. 选择功能:支持单选或多选模式,轻松实现表格行的选择事件处理;
  6. 更多扩展特性:预留接口和配置项,支持排序、筛选、自定义列渲染等高级功能,以适应多样化的业务场景。

通过这些特性,我们的通用业务表格组件不仅简化了开发流程,还极大地提高了代码的复用性和项目的整体效率。

接下来,我们将详细介绍如何实现这一通用业务表格的封装。

二、封装步骤

步骤一:创建通用表格组件结构

  1. 创建组件文件 :在 Vue 项目中创建一个名为 CommonTable.vue 的文件。
  2. 定义组件模板 :在 <template> 标签内,定义表格的结构,包括表格头部、主体和分页。
html 复制代码
<template>
  <div class="table-main">
    <!-- 表格头部 操作按钮 -->
    <div class="table-header">
      <div class="header-button-lf">
        <slot name="tableHeader"/>
      </div>
      <div class="header-button-ri">
        <slot name="toolButton"/>
      </div>
    </div>
    <!-- 表格主体 -->
    <el-table
      ref="table"
      v-bind="$attrs"
      :data="tableData"
      :header-cell-style="cellStyle"
      @row-click="rowClick"
      :border="border"
      :rowKey="rowKey"
      :height="height"
      :lazy="lazy"
      :tree-props="treeProps"
      :max-height="maxHeight"
      @selection-change="selectionChange"
    >
      <!-- 默认插槽 -->
      <slot/>
      <template v-for="(item, index) in columns">
        <el-table-column
          v-if="item.prop !== 'operation'"
          :key="index"
          v-bind="item"
          :align="item.align? item.align : 'center'"
        >
          <template v-slot:default="scope" v-if="item.slotName">
            <!-- 这里展示 自定义 插槽内容 -->
            <slot :name="item.slotName" v-bind="scope"/>
          </template>
          <template v-if="item.children">
            <el-table-column
              v-for="(child, iex) in item.children"
              :key="iex"
              v-bind="child"
              :align="item.align? item.align : 'center'"
            >
              <template v-slot:default="scope" v-if="item.slotName">
                <!-- 这里展示 自定义 插槽内容 -->
                <slot :name="item.slotName" v-bind="scope"/>
              </template>
            </el-table-column>
          </template>
        </el-table-column>
        <el-table-column
          v-if="item.prop === 'operation'"
          :key="index"
          v-bind="item"
          :align="item.align? item.align : 'center'"
        >
          <template v-slot:default="scope">
            <!-- 这里展示 operation 插槽内容 -->
            <slot name="operation" v-bind="scope"/>
          </template>
        </el-table-column>
      </template>
      <template #empty>
        <el-empty :image-size="300" description="暂无数据"></el-empty>
      </template>
    </el-table>
    <!-- 分页组件 -->
    <div class="pagination">
      <el-pagination
        v-if="pagination"
        @size-change="handleSizeChange"
        @current-change="handleCurrentChange"
        :current-page="pageParam.pageNum"
        :page-sizes="[10, 20, 30, 40, 50, 100]"
        :page-size="pageParam.pageSize"
        layout="total, sizes, prev, pager, next, jumper"
        :total="total"
      />
    </div>
  </div>
</template>

表格头部容器 .table-header 这是一个包裹所有头部内容的容器

操作按钮区域 .header-button-lf.header-button-ri 这个区域用于放置表格的头部操作按钮,它通过一个名为 tableHeader yu toolButton 的插槽来实现内容的自定义。这意味着在使用 CommonTable 组件时,你可以通过这个插槽插入任何自定义的头部内容,比如搜索框、筛选器等。

表格主体 以下是对 <el-table> 组件及其示例属性的讲解:

  • ref="table":为表格设置引用名称,方便在 Vue 组件中通过 this.$refs.table 访问表格实例。
  • v-bind="$attrs":将父组件传递给子组件的所有非 prop 属性绑定到 <el-table> 上,使得可以传递更多属性。
  • :data="tableData":绑定表格数据,tableData 是一个数组,数组中的每个对象代表表格的一行。
  • :header-cell-style="cellStyle":自定义表头单元格的样式。
  • @row-click="rowClick":监听行点击事件,当点击某一行时触发 rowClick 方法。
  • :border="border":设置表格是否带有边框。
  • :rowKey="rowKey":行的 key,用于优化渲染。
  • :height="height":表格的高度,如果设置了这个属性,表格会固定高度并出现滚动条。
  • :lazy="lazy":是否懒加载子节点数据。
  • :tree-props="treeProps":树形表格的配置选项。
  • :max-height="maxHeight":表格的最大高度。
  • @selection-change="selectionChange":当选择项发生变化时会触发这个事件。

插槽 <slot/> 这是一个默认插槽,允许你在 <el-table> 组件内部插入任何内容,比如自定义的列或者行。

列的循环渲染 使用 v-for 指令循环 columns 数组,为每个列定义 <el-table-column> 组件。

  • v-if="item.prop !== 'operation'":判断当前列是否为操作列,如果不是,则渲染常规列。
  • :key="index":为每个列设置唯一的 key 值,通常是列的索引。
  • v-bind="item":将列的配置对象绑定到 <el-table-column> 上。
  • :align="item.align? item.align : 'center'":设置列的对齐方式,默认为居中。

自定义插槽内容 如果列配置中有 slotName 属性,则表示该列需要自定义渲染内容。使用 <slot :name="item.slotName" v-bind="scope"/> 插槽来展示自定义内容。

子列的渲染 如果列配置中有 children 属性,表示这是一个分组列,需要递归渲染子列。

操作列的渲染 如果列的 prop 属性值为 'operation',则渲染操作列。操作列通常包含对当前行的操作按钮。

  • <slot name="operation" v-bind="scope"/>:使用名为 operation 的插槽来展示操作按钮。

空状态插槽 使用 #empty 插槽来定义当表格没有数据时的展示内容。这里使用了 <el-empty> 组件来显示"暂无数据"的信息

步骤二:定义组件的 props 和 events

  1. 定义 props :在 <script> 标签内的 export default 对象中,定义组件接收的属性。
  2. 定义 events :同样在 <script> 标签内,定义组件触发的事件。

在 Vue 组件中,propsevents 是组件与外部环境通信的关键机制。以下是对 CommonTable 组件中定义的 propsevents 的详细讲解:

html 复制代码
<script>
export default {
  name: 'CommonTable',
  props: {
    lazy: {
      type: Boolean,
      default: false
    },
    treeProps: {
      type: Object,
      default() {
        return {}
      }
    },
    rowKey: {
      type: String,
      default: ''
    },
    height: {
      type: [String, Number],
      default: '100%'
    },
    // 表格最高高度
    maxHeight: {
      type: [String, Number],
      default: '100%'
    },
    // 表格边框
    border: {
      type: Boolean,
      default: true
    },
    // 表格数据
    tableData: {
      type: Array,
      default() {
        return [];
      }
    },
    // 表格列
    columns: {
      type: Array,
      default() {
        return [];
      }
    },
    // 表格分页组件 ==> 非必传(默认为true)
    pagination: {
      type: Boolean,
      default: true
    },
    total: {
      type: Number,
      default: 0
    },
    // 表格表头样式
    cellStyle: {
      type: Object,
      default() {
        return {};
      },
      required: false
    }
  },
  data() {
    return {
      // 分页参数
      pageParam: {
        pageSize: 10,
        pageNum: 1
      }
    };
  },
  methods: {
    rowClick(row) {
      this.$emit("rowClick", row)
    },
    // 表格多选
    selectionChange(val) {
      this.$emit('selectionChange', val);
    },
    // 每页条数
    handleSizeChange(val) {
      this.pageParam.pageSize = val;
      this.pageParam.pageNum = 1; // 切换每页显示条数时,将页码重置为 1
      this.$emit('upPage', this.pageParam);
    },
    // 当前页
    handleCurrentChange(val) {
      this.pageParam.pageNum = val;
      this.$emit('upPage', this.pageParam);
    }
  }
};
</script>

Props

props 是组件的自定义属性,允许父组件向子组件传递数据。

  1. lazy:指示表格是否开启懒加载,懒加载通常用于树形表格或大量数据的分页加载。

  2. treeProps:当表格为树形表格时,该属性用于配置树形表格的属性,如子节点键名等。

  3. rowKey:表格行的 key 值,用于优化渲染性能,特别是在进行排序或筛选操作时。

  4. height:表格的高度,可以是像素值或百分比。

  5. maxHeight:表格的最大高度,当内容超出此高度时,将显示滚动条。

  6. border:是否显示表格的边框。

  7. tableData:表格的数据源,每个数组元素代表表格的一行。

  8. columns:表格的列配置,数组中的每个对象定义了列的属性,如列名、数据字段等。

  9. pagination:是否显示分页组件。

  10. total:表格数据的总条数,用于分页组件计算总页数。

  11. cellStyle:自定义表头单元格的样式。

Events

events 是组件的自定义事件,允许子组件向父组件发送消息或通知。

  1. rowClick:当表格的某一行被点击时触发,传递被点击的行数据作为参数。

  2. selectionChange:当表格的选择项发生变化时触发,传递当前选择的行数据数组作为参数。

  3. upPage:当分页参数发生变化时触发,传递当前的 pageParam 对象作为参数,该对象包含 pageSizepageNum 属性。

Methods

以下是组件内部定义的方法,用于处理事件和逻辑:

  1. rowClick(row):当行被点击时调用,触发 rowClick 事件,并将当前行数据传递给父组件。

  2. selectionChange(val): 当表格的选择项发生变化时调用,触发 selectionChange 事件,并将选择的行数据数组传递给父组件。

  3. handleSizeChange(val):当分页组件的每页显示条数发生变化时调用,更新 pageParam 对象,并触发 upPage 事件。

  4. handleCurrentChange(val):当分页组件的当前页码发生变化时调用,更新 pageParam 对象,并触发 upPage 事件。

通过这些 propseventsCommonTable 组件可以灵活地接收外部数据,同时也能够将内部状态和事件通知给外部,从而实现组件的复用和高度定制化。

CommonTable 组件的使用

js 复制代码
<template>
    <CommonTable
      :tableData="data"
      v-loading="loading"
      :columns="columns"
      :total="total"
      row-key="id"
      :lazy="true"
      :treeProps="{children: 'children', hasChildren: 'hasChildren'}"
      @upPage="getUpPage"
      @selectionChange="handleSelectionChange"
    >
      <template #toolButton>
        <el-button class="filter-item" size="mini" type="primary" @click="add">添加</el-button>
      </template>
      <template #operation="scope">
        <el-button size="mini" type="text" @click="edit(scope.row)">编辑</el-button>
        <el-button size="mini" type="text" @click="copy(scope.row)">复制</el-button>
        <el-button size="mini" type="text">发布</el-button>
        <el-button size="mini" type="text">下架</el-button>
        <el-button size="mini" type="text">删除</el-button>
      </template>
      <template #jobTest="scope">
         <span>{{scope.row.jobTest}} </span>
      </template>
      <template #Status="scope">
         <span>
            {{scope.row.Status === '00'?'未发布':(scope.row.Status ==='01'?'测评中'(scope.row.Status === '02'?'已结束':'已下架'))}}
          </span>
      </template>
      <template #operation="scope">
          <el-button type="text" @click="checkOut('查看', scope.row)">查看</el-button>
          <el-button type="text" @click="checkOut('审核', scope.row)">审核</el-button>
      </template>
    </CommonTable>
</template>
export default {
    data(){
        return {
            multipleSelection: [],
            pageParam: {
              pageNum: 1, // 当前页码
              pageSize: 10 // 每页显示的数据条数
            }
            columns: [
              {type: 'selection', minWidth: 50},
              {prop: 'Account', label: '账号', minWidth: 300},
              {prop: 'Name', label: '名称', minWidth: 200},
              {prop: 'Time', label: '最近登录时间', minWidth: 300},
              {prop: 'jobTestName', label: '测评标题', minWidth: 160,slotName: 'jobTest'},
              {prop: 'Status', label: '发布状态', minWidth: 100,slotName: 'Status'},
              {
                prop: 'publish',
                label: '审核状态',
                minWidth: 110,
                formatter: function (row, column, cellValue) {
                const option = shzt.find((opt) => opt.value == cellValue);
                return option ? option.label : cellValue;
                }
              },
              {
                prop: 'accountStatus',
                label: '账号状态',
                minWidth: 100,
                formatter: function (row, column, cellValue) {
                  switch (cellValue) {
                    case '01':
                      return '已启用';
                    default:
                      return '已挂起';
                  }
                }
              },
              {prop: 'operation', label: '操作', fixed: 'right', minWidth: 100}
            ]
        }
    },
    methods: {
        // 查询按钮
        searchData() { },
        // 查看 审核
        checkOut(val, row) {  },
        getUpPage(pageParam) {
          this.pageParam = pageParam;
          this.searchData();
        },
        // 选中数据
        handleSelectionChange(val) {
          this.multipleSelection = val
       },
  }
}

这段代码展示了如何在 Vue 组件中使用 ShareTable 组件,这是一个经过二次封装的表格组件,用于展示和操作数据。以下是对代码的详细解释:

CommonTable 组件被用于显示表格数据,并提供了分页、加载状态、列配置等功能。以下是对 CommonTable 组件属性和插槽的说明:

  • columns 数组定义了表格的列配置,包括列的类型、属性、标签、宽度、对齐方式等。还使用了 formatter 函数来格式化特定列的显示值,例如将账号状态码转换为文字描述。
  • :tableData="data":绑定表格数据源。
  • v-loading="loading":绑定加载状态,用于显示或隐藏加载动画。
  • :columns="columns":绑定表格列配置。
  • :total="total":绑定表格数据的总条数,用于分页。
  • row-key="id":指定表格行的唯一键值,用于树形表格或虚拟滚动。
  • :lazy="true":启用懒加载,适用于树形表格。
  • :treeProps="{children: 'children', hasChildren: 'hasChildren'}":配置树形表格的子节点属性。
  • @upPage="getUpPage":监听分页参数变化的事件。
  • @selectionChange="handleSelectionChange":监听表格选择项变化的事件。
  • #toolButton:在表格头部插入工具按钮,如添加、删除等。
  • #operation:在表格每行的操作列插入操作按钮,如编辑、删除等。
  • #jobTest#Status:自定义列内容的显示。
  • #operation 插槽中,定义了多个操作按钮,如查看、审核、启用、挂起等

下面是 .table-main 组件的样式,包括表格主体、表格头部和分页器的布局与样式。

scss 复制代码
<style lang="scss" scoped>
.table-main {
  height: 100%;
  display: flex;
  flex-direction: column;

  .table-header {
    display: flex;
    margin: 10px 0;
    justify-content: space-between;
  }

  .el-table {
    flex: 1;
  }

  .pagination {
    width: 100%;
    padding: 15px 0;
    background-color: #fff;
  }
}
</style>
<style>
/* 限制 el-tooltip 内容的宽度并允许文本换行 */
.el-tooltip__popper {
  max-width: 400px; /* 你可以根据需要调整这个值 */
  white-space: normal !important;
}

/* 确保 tooltip 中的文字能够正确换行 */
.el-tooltip__popper p,
.el-tooltip__popper div {
  white-space: normal !important;
}
</style>

总结

这段代码是一个典型的 Vue 组件使用示例,它展示了如何利用 CommonTable 组件的属性、事件和插槽来构建一个具有丰富功能的表格界面。通过这种方式,可以轻松地对表格进行定制,以适应不同的业务场景和需求。打造一个功能丰富的通用业务表格组件。在实际项目中,我们可以根据业务需求调整和扩展这个组件,从而提高开发效率和代码复用性。

相关推荐
轻口味29 分钟前
命名空间与模块化概述
开发语言·前端·javascript
前端小小王1 小时前
React Hooks
前端·javascript·react.js
迷途小码农零零发1 小时前
react中使用ResizeObserver来观察元素的size变化
前端·javascript·react.js
娃哈哈哈哈呀2 小时前
vue中的css深度选择器v-deep 配合!important
前端·css·vue.js
旭东怪2 小时前
EasyPoi 使用$fe:模板语法生成Word动态行
java·前端·word
ekskef_sef4 小时前
32岁前端干了8年,是继续做前端开发,还是转其它工作
前端
sunshine6414 小时前
【CSS】实现tag选中对钩样式
前端·css·css3
真滴book理喻4 小时前
Vue(四)
前端·javascript·vue.js
蜜獾云4 小时前
npm淘宝镜像
前端·npm·node.js