简易封装element-plus table表格组件

161 阅读1分钟

因日常工作会大量使用table表格,今天就封装一个简易版本, 话不多说上代码!

<script setup>
import { reactive, watch } from "vue";
const props = defineProps({
  staticStatePaging: {
    type: Boolean,
    default: false,
  },
  //   表格配置
  tableConfig: {
    type: Object,
    required: true,
    default() {
      return {
        stripe: true,
        pageSizeArr: [10, 20, 50, 100],
        border: false, // 是否带有纵向边框,默认为false
        hasSelect: false, // 有无选中功能
        hasOperation: false, // 有无操作功能
        hasExpand: false, // 有无展开行功能
        rowClick: false, // 是否开启行点击
        columns: [],
        operation: {},
        expands: [],
        searchProp: {},
        pagination: {},
        formatTableData: (res) => res,
      };
    },
  },
  // 请求配置  返回一个·promise
  requestFun: {
    type: Function,
  },
  tableDataProp: {
    type: Array,
    default: () => {
      return [];
    },
  },
  tableDataPropTotal: {
    type: Number,
    default: 0,
  },
  // 动态配置项(查询参数)
  requestData: {
    type: Object,
    default() {
      return {
        requestParamsOrData: {
          current: 1,
          pageSize: 10,
        },
      };
    },
  },
  // 初始不发请求(适用于页面初始加载业务组件传参查询的情况)
  initPersonTable: {
    type: Boolean,
    default: false,
  },
});
const tableMsg = reactive({
  data: [],
  totalCount: 0,
  loading: false,
});

// 事件注册
const emit = defineEmits([
  "onHandleSizeChange",
  "onHandleCurrentChange",
  "update:requestParamsOrData",
  "onOperateBtn",
]);

watch(
  () => props.tableDataProp,
  (newV) => {
    if (props.staticStatePaging) {
      if (newV?.length > props.requestData.requestParamsOrData.pageSize) {
        tableMsg.data = newV.slice(
          0,
          props.requestData.requestParamsOrData.pageSize
        );
        emit("update:requestParamsOrData", {
          ...props.requestData.requestParamsOrData,
          current: 1,
        });
      } else {
        tableMsg.data = newV;
      }
      tableMsg.totalCount = newV.length;
    } else {
      tableMsg.data = newV;
      tableMsg.totalCount = props.tableDataPropTotal;
    }
  },
  { deep: true, immediate: true }
);
watch(
  () => props.requestData,
  () => {
    if (props.requestFun) {
      getData();
    }
  },
  {
    deep: true,
  }
);

const getData = async () => {
  tableMsg.loading = true;
  const config = formatSearch();
  const formatData = props.tableConfig.formatTableData;
  if (props.requestFun) {
    await props.requestFun(config.data, config.params).then(
      async (res) => {
        tableMsg.loading = false;
        tableMsg.data = formatData(res).data;
        tableMsg.totalCount = formatData(res).totalCount;
      },
      () => {
        tableMsg.data = [];
        tableMsg.totalCount = 0;
        tableMsg.loading = false;
      }
    );
  } else {
    tableMsg.loading = false;
  }
};

// 格式化请求参数
const formatSearch = () => {
  let params = {};
  let data = {};
  for (const k in props.requestData.requestParamsOrData) {
    if (
      props.tableConfig?.searchProp?.[k] &&
      props.tableConfig?.searchProp?.[k] === "params"
    ) {
      params = {
        ...params,
        [k]: props.requestData.requestParamsOrData[k],
      };
    } else {
      data = {
        ...data,
        [k]: props.requestData.requestParamsOrData[k],
      };
    }
  }
  const finalObj =
    JSON.stringify(params) === "{}" ? { data } : { params, data };
  return finalObj;
};
const handleSizeChange = (val) => {
  if (props.staticStatePaging) {
    emit("update:requestParamsOrData", {
      ...props.requestData.requestParamsOrData,
      pageSize: val,
    });
    let num = val;
    let currentPage = props.requestData.requestParamsOrData.current;
    let totalNum = (currentPage - 1) * num;
    tableMsg.data = props.tableDataProp.slice(totalNum, num + totalNum) || [];
  } else {
    emit("onHandleSizeChange", val);
  }
};

const handleCurrentChange = (val) => {
  if (props.staticStatePaging) {
    emit("update:requestParamsOrData", {
      ...props.requestData.requestParamsOrData,
      current: val,
    });
    let num = props.requestData.requestParamsOrData.pageSize;
    let currentPage = val;
    let totalNum = (currentPage - 1) * num;
    tableMsg.data = props.tableDataProp.slice(totalNum, num + totalNum) || [];
  } else {
    emit("onHandleCurrentChange", val);
  }
};

const handleOperation = (item, row) => {
  emit("onOperateBtn", {
    item,
    row,
  });
};

getData();

</script>

<template>
  <div>
    <el-table
      :data="tableMsg.data"
      :key="tableConfig.key || 'myTable'"
      v-loading="tableMsg.loading"
      :tableConfig="tableConfig"
      :max-height="tableConfig.height || '650'"
      :height="tableConfig.minHeight"
      style="width: 100%"
      :header-cell-style="{
        background: '#f0f1f5',
        color: '#000000',
      }"
    >
      <el-table-column
        v-for="item in tableConfig.columns"
        :key="item.id"
        :label="item.label"
        :prop="item.prop"
        :class-name="item.className ? item.className : ''"
        :width="item.width ? item.width : ''"
        :sortable="item.sortable"
        :min-width="item.minWidth ? item.minWidth : ''"
        :show-overflow-tooltip="!item.hideTooltip"
        :fixed="item.fixed"
        :align="item.align"
      >
        <template v-slot="scope">
          <!-- 自定义模板  使用slot -->
          <template
            v-if="item.show === 'template' || item.showType === 'template'"
          >
            <slot :name="item.prop" :scope="scope" />
          </template>
          <!-- 正常渲染数据列 -->
          <template v-else-if="item.show === 'function'">
            {{ item.valueFun(scope.row[item.prop], scope.row) }}
          </template>
          <template v-else-if="item.show !== 'template'">
            {{
              item.formatData
                ? item.formatData(scope.row[item.prop])
                : scope.row[item.prop]
            }}
          </template>
        </template>
      </el-table-column>
      <!-- 操作列 -->
      <el-table-column
        v-if="tableConfig.hasOperation"
        column-key="operation"
        :label="tableConfig.operation.label"
        :width="tableConfig.operation.width ? tableConfig.operation.width : ''"
        :min-width="
          tableConfig.operation.minWidth ? tableConfig.operation.minWidth : ''
        "
        :class-name="tableConfig.operation.className"
        :fixed="tableConfig.operation.fixed"
      >
        <template v-slot="scope">
          <slot name="operation" :scope="scope">
            <el-button
              v-for="item in tableConfig.operation.data"
              :key="item.id"
              :class="item.className ? item.className : ''"
              :size="item.size || 'small'"
              :type="item.type || 'info'"
              :link="item.link || true"
              :text="item.text || true"
              @click.stop="handleOperation(item, scope.row)"
            >
              {{ item.label }}
            </el-button>
          </slot>
        </template>
      </el-table-column>
    </el-table>
    <div class="clearfix">
      <el-pagination
        v-if="tableConfig.pagination && !tableConfig.pagination.hidden"
        :background="
          tableConfig.pagination && tableConfig.pagination.background
        "
        :current-page="requestData.requestParamsOrData.current"
        :page-sizes="tableConfig.pageSizeArr"
        :page-size="requestData.requestParamsOrData.pageSize"
        layout="sizes,prev, pager, next,jumper"
        :total="tableMsg.totalCount"
        @size-change="handleSizeChange"
        @current-change="handleCurrentChange"
      />
    </div>
  </div>
</template>
<style lang="less" scoped>
.clearfix {
  display: flex;
  justify-content: flex-end;
  margin-top: 18px;
}
</style>

myTableMixin.js

export default function (requestData) {
      const onHandleSizeChange = (val) => {
        requestData.requestParamsOrData = {
          ...requestData.requestParamsOrData,
          pageSize: val,
        };
      };
      const onHandleCurrentChange = (val) => {
        requestData.requestParamsOrData = {
          ...requestData.requestParamsOrData,
          current: val,
        };
      };

      return {
        onHandleCurrentChange,
        onHandleSizeChange,
      };
}

使用

先引入myTableMixin.js

image.png

// 请求数据
requestData.requestParmasOrData = {
    ...requestData.requestParmasOrData,
}

目前只封装一个简易版本,后续再扩展其他表格功能... 第一次写文章好紧张,望各位大佬提出宝贵意见!顺便给小弟点点赞,哈哈哈哈哈哈