elementPlus表格二次封装

为何要对element-plus表格进行二次封装?

  • 我们正常在开发项目中,表格的风格是一致的,但是表格或多或少会有些不同,有些是需要分页,有些是按钮功能不同,有些又需要加Tag,或者对时间进行格式化等。所有才有了对element-plus的二次封装。

优势

  1. 组件中集成表格、分页、loading、tag等功能。
  2. 统一项目表格整体风格。
  3. 快速将表格在分页与不分页间切换。
  4. 表格列可根据需求进行定制化。
  5. 可快速开发大量自定义表格。

例子

html 复制代码
<ELTable
  class="table"
  :table-data="tableObject.tableData"
  :columns="tableObject.columns"
  :page-config="tableObject.pageConfig"
  @current-change="onCurrentTableChange"
>
  <template #operate="{ scope }">
    <el-button size="small" @click="handleEdit(scope)">Edit</el-button>
    <el-button size="small" type="danger" @click="handleDelete(scope)"
      >Delete</el-button
    >
  </template>
</ELTable>

参数

  • tableData 表格的数据
js 复制代码
{
   tableData: any[];
}
  • columns 列配置
js 复制代码
type TableColumnType = {
    prop: string;
    label: string;
    attrs?: any;
    slot?: boolean;
    tagList?: TagObjectType[];
};

{
    columns: TableColumnType[];
};
  • pageConfig 页面配置
js 复制代码
type PageConfigType = {
  pageSize: number,
  total: number,
  pagerCount?: number,
  currentPage: number,
  // eslint-disable-next-line no-unused-vars
  handleCurrentChange: (val: number) => void
};

{
  pageConfig: PageConfigType;
}
  • currentChange 点击分页后的事件
js 复制代码
 {
   currentPageChange: (val: number,oldVal: number) => void;
 }
  • 整体简单配置
ts 复制代码
<ELTable
  class="table"
  :table-data="tableObject.tableData"
  :columns="tableObject.columns"
  :page-config="tableObject.pageConfig"
  @current-change="onCurrentTableChange"
>
</ELTable>

const tableObject = reactive<TableType>({
  columns: [
    {
      prop: 'date',
      label: 'Date',
      attrs: {
        width: 140
      }
    },
    {
      prop: 'alarm',
      label: '告警等级',
      attrs: {
        width: 100
      }
    }
  ],
  pageConfig: {
    pageSize: 5,
    total: 100,
    pagerCount: 5,
    currentPage: 3,
    handleCurrentChange: (number: number) => {
      console.log('重新请求数据', number);
    }
  },
  tableData: [
    {
      date: '2016-05-03',
      alarm: '1'
    },
    {
      date: '2016-05-02',
      alarm: '4'
    }
  ]
});

简单的例子

带分页表格 usePagination

  • 添加 usePaginnation后即可实现表格分页的功能,@current-change是当分页页面变化时的回调
ts 复制代码
<ELTable
  class="table"
  :table-data="tableObject.tableData"
  :columns="tableObject.columns"
  :page-config="tableObject.pageConfig"
  usePagination
>
</ELTable>

const tableObject = reactive<TableType>({
  columns: [],
  pageConfig: {
    pageSize: 5,
    total: 100,
    pagerCount: 5,
    currentPage: 3,
    // 当前页发生变化时的回调
    handleCurrentChange: (number: number) => {
    tableObject.pageConfig.currentPage = number;
      console.log('重新请求当前页的数据数据', number);
    }
  },
  tableData: []
});

不带分页的表格

  • 不带分页的表格只需要将 usePagination 设置为false,pageConfig项可以不设置即可
ts 复制代码
<ELTable
  class="table"
  :table-data="tableObject.tableData"
  :columns="tableObject.columns"
  :usePagination="false"
>
</ELTable>

const tableObject = reactive<TableType>({
  columns: [],
  tableData: []
});

带 tag 的表格

html 复制代码
<ELTable
  class="table"
  :table-data="tableObject.tableData"
  :columns="tableObject.columns"
  :page-config="tableObject.pageConfig"
>
</ELTable>
  • 需要在 columns 下配置 tagList
ts 复制代码
import ELTable, { TableType } from '@/components/Table.vue';

const tableObject = reactive<TableType>({
  columns: [
    {
      prop: 'date',
      label: 'Date',
      attrs: {
        width: 140
      }
    },
    {
      prop: 'name',
      label: 'Name',
      attrs: {
        width: 80
      }
    },
    {
      prop: 'address',
      label: 'Address',
      attrs: {
        width: 180
      }
    },
    {
      prop: 'alarm',
      label: '告警等级',
      attrs: {
        width: 100
      },
      tagList: [
        {
          label: '严重',
          value: '1',
          className: 'error'
        },
        {
          label: '紧急',
          value: '2',
          className: 'warning'
        },

        {
          label: '一般',
          value: '3',
          className: 'info'
        },
        {
          label: '提示',
          value: '4',
          className: 'success'
        }
      ]
    }
  ],
  pageConfig: {
    pageSize: 5,
    total: 100,
    pagerCount: 5,
    currentPage: 3,
    handleCurrentChange: (number: number) => {
      console.log('重新请求数据', number);
    }
  },
  tableData: [
    {
      date: '2016-05-03',
      name: 'Tom',
      address: 'No. 189, Grove St, Los Angeles',
      alarm: '1'
    },
    {
      date: '2016-05-02',
      name: 'Tom',
      address: 'No. 189, Grove St, Los Angeles',
      alarm: '4'
    },
    {
      date: '2016-05-04',
      name: 'Tom44',
      address: 'No. 189, Grove St, Los Angeles',
      alarm: '3'
    },
    {
      date: '2016-05-01',
      name: 'Tom55',
      address: 'No. 189, Grove St, Los Angeles',
      alarm: '1'
    },
    {
      date: '2016-05-01',
      name: 'Tom55',
      address: 'No. 189, Grove St, Los Angeles',
      alarm: '1'
    }
  ]
});

带按钮的表格

  • 带按钮的表格一般是需要自定义模板的 。需要在 columns 下面的配置项中添加操作选项。然后插槽名则是 prop 的值。
html 复制代码
<ELTable
  class="table"
  :table-data="tableObject.tableData"
  :columns="tableObject.columns"
  :page-config="tableObject.pageConfig"
  @current-change="onCurrentTableChange"
>
  <template #operate="{ scope }">
    <el-button size="small" @click="handleEdit(scope)">Edit</el-button>
    <el-button size="small" type="danger" @click="handleDelete(scope)"
      >Delete</el-button
    >
  </template>
</ELTable>
ts 复制代码
import ELTable, { TableType } from '@/components/Table.vue';
const tableObject = reactive<TableType>({
  columns: [
    {
      prop: 'date',
      label: 'Date',
      attrs: {
        width: 140
      }
    },
    {
      prop: 'name',
      label: 'Name',
      attrs: {
        width: 80
      }
    },
    {
      prop: 'address',
      label: 'Address',
      attrs: {
        width: 180
      }
    },
    {
      prop: 'alarm',
      label: '告警等级',
      attrs: {
        width: 100
      },
      tagList: [
        {
          label: '严重',
          value: '1',
          className: 'error'
        },
        {
          label: '紧急',
          value: '2',
          className: 'warning'
        },

        {
          label: '一般',
          value: '3',
          className: 'info'
        },
        {
          label: '提示',
          value: '4',
          className: 'success'
        }
      ]
    },
    {
      prop: 'operate',
      label: '操作',
      slot: true,
      attrs: {
        width: '180'
      }
    }
  ],
  pageConfig: {
    pageSize: 5,
    total: 100,
    pagerCount: 5,
    currentPage: 3,
    handleCurrentChange: (number: number) => {
      console.log('重新请求数据', number);
    }
  },
  tableData: [
    {
      date: '2016-05-03',
      name: 'Tom',
      address: 'No. 189, Grove St, Los Angeles',
      alarm: '1'
    },
    {
      date: '2016-05-02',
      name: 'Tom',
      address: 'No. 189, Grove St, Los Angeles',
      alarm: '4'
    },
    {
      date: '2016-05-04',
      name: 'Tom44',
      address: 'No. 189, Grove St, Los Angeles',
      alarm: '3'
    },
    {
      date: '2016-05-01',
      name: 'Tom55',
      address: 'No. 189, Grove St, Los Angeles',
      alarm: '1'
    },
    {
      date: '2016-05-01',
      name: 'Tom55',
      address: 'No. 189, Grove St, Los Angeles',
      alarm: '1'
    }
  ]
});

配置插槽

如果在columns中配置了 sort:true。默认就会读取表格中插槽名称为 props值的结构,放入当前列。

js 复制代码
<ELTable
  class="table"
  :table-data="tableObject.tableData"
  :columns="tableObject.columns"
  :page-config="tableObject.pageConfig"
  @current-change="onCurrentTableChange"
>
  <template #aaa="{ scope }">
    <el-button size="small" @click="handleEdit(scope)">Edit</el-button>
    <el-button size="small" type="danger" @click="handleDelete(scope)"
      >Delete</el-button
    >
  </template>
</ELTable>

<script>
import ELTable, { TableType } from '@/components/Table.vue';
const tableObject = reactive<TableType>({
  columns: [
    {
      prop: 'aaa',
      label: '操作',
      attrs: {
        width: '180'
      },
      slot: true // 属性为true时 插槽生效,并读取属性名为 aaa 的插槽。
    },

  ],
});
</script>

配置表格列的原生属性

  • 如果想要配置表格列的原生属性。可以在clounms下的 attrs 中去配置,例如:想要配置 fixedresizableformatter 等...
js 复制代码
import ELTable, { TableType } from '@/components/Table.vue';
const tableObject = reactive<TableType>({
  columns: [
    {
      prop: 'date',
      label: 'Date',
      attrs: {
      // 配置表格的原生属性
        width: 140
        fixed: true,
        resizable: true
        formatter: function(row,column) {
          console.log('过滤器')
        }
      }
    },

  ],
});

当前项高亮时触发的方法@selection-change

js 复制代码
<ELTable
  class="table"
  :table-data="tableObject.tableData"
  :columns="tableObject.columns"
  :page-config="tableObject.pageConfig"
  @selection-change="onSelectionChange"
  highlight-current-row
  stripe
>
</ELTable>

const onSelectionChange = (row) => {
  console.log('选中当前项时会触发的事件')
}

table表格封装的源码

ts 复制代码
<template>
    <div class="cus-table">
        <el-table v-loading="props.loading" :data="props.tableData" style="width: 100%" v-bind="$attrs">
            <el-table-column v-for="column in props.columns" :key="column.prop" :prop="column.prop" :label="column.label" width="180" v-bind="column?.attrs">
                <!-- 默认有插槽的情况 -->
                <template #default="scope">
                    <slot v-if="column.slot" :name="column.prop" :scope="scope" />
                    <!-- 当有告警时表格默认做出处理 -->
                    <template v-if="column.tagList?.length">
                        <div v-for="(tag, index) in filteredTagList(scope.row, column.tagList, column.prop)" :key="tag.value + '_' + index">
                            <div class="tag" :class="tag.className">{{ tag.label }}</div>
                        </div>
                    </template>
                </template>
            </el-table-column>
        </el-table>

        <!-- 分页 -->
        <template v-if="props.usePagination">
            <div class="pagination">
                <div>总共 {{ pageConfig.total }} 条信息</div>
                <el-pagination
                    v-model:current-page="currentPage"
                    class="cus-pagination"
                    background
                    layout="prev, pager, next"
                    :page-size="pageConfig.pageSize"
                    :total="pageConfig.total"
                    :pager-count="pageConfig.pagerCount"
                    @current-change="pageConfig.handleCurrentChange"
                />
            </div>
        </template>
    </div>
</template>

<script setup lang="ts">
type TagObjectType = {
    label: string;
    value: string;
    className: 'error' | 'warning' | 'info' | 'success' | 'offline';
};

type PageConfigType = {
    pageSize: number;
    total: number;
    pagerCount?: number;
    currentPage: number;
    // eslint-disable-next-line no-unused-vars
    handleCurrentChange?: (val: number) => void;
};

type TableColumnType = {
    prop: string;
    label: string;
    attrs?: any;
    slot?: boolean;
    tagList?: TagObjectType[];
};

export type TableType = {
    tableData: any[];
    columns: TableColumnType[];
    pageConfig?: PageConfigType;
    loading?: boolean;
    usePagination?: boolean;
};

const props = withDefaults(defineProps<TableType>(), {
    tableData: () => [],
    columns: () => [],
    pageConfig: () => ({
        pageSize: 5,
        total: 0,
        currentPage: 1,
    }),
    loading: false,
    usePagination: true,
});

const filteredTagList = (scope: any, tagList: any[], prop: string) => tagList?.filter((tag: any) => tag?.value === scope?.[prop]);

const currentPage = ref(props.pageConfig.currentPage);
</script>

<style lang="scss" scoped>
.error {
    background-color: rgba(171, 1, 0, 0.2);
    border: 2px solid rgba(255, 78, 77, 1);
}

.warning {
    background-color: rgba(185, 74, 0, 0.2);
    border: 2px solid rgba(255, 128, 15, 1);
}

.info {
    background-color: rgba(174, 127, 0, 0.2);
    border: 2px solid rgba(255, 235, 15, 1);
}

.tootip {
    background-color: rgba(0, 82, 183, 0.2);
    border: 2px solid rgba(61, 148, 255, 1);
}

.success {
    background-color: rgba(39, 191, 114, 0.2);
    border: 2px solid rgba(71, 221, 145, 1);
}

.offline {
    background-color: rgba(154, 158, 174, 0.2);
    border: 2px solid rgba(154, 158, 174, 1);
}

.cus-table {
    width: 100%;
    position: relative;
    overflow: hidden;

    .tag {
        display: flex;
        justify-content: center;
        align-items: center;
        width: 60px;
        height: 24px;
        color: #ffffff;
        opacity: 0.6;
        border-radius: 12px;
    }

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