element el-table表格二次封装

217 阅读2分钟

123.png

“table表格在项目中非常常见,项目基本上都能用到,为了更高效的开发,我们可以将其封装的更为简洁!先来看一下效果”

效果如下:

image.png

“表格支持el-table属性大部分属性,也可扩展,提供封装思路”

废话少说上代码

1.封装组件

1.huTable.vue

<template>
<el-table
  v-bind="$attrs"
  v-on="$listeners"
  ref="multipleTable"
  :key="key"
  v-loading="loading"
  :data="tableData"
  @cell-dblclick="cellDblclick"
>
  <hu-table-column
    v-bind="item"
    v-for="item in bindTableCol"
    :key="item.prop"
    @cellDblclick="cellDblclick"
    :item="item"
    slot=""
  >
    <template v-if="item.slot" v-slot:[item.slot]="{ row, column, $index }">
      <slot
        :name="item.slot"
        :$index="$index"
        :row="row"
        :column="column"
      ></slot>
    </template>
  </hu-table-column>
</el-table>
</template>

<script>
import huTableColumn from "./huTableColumn.vue";
export default {
name: "HuTable",
components: {
  huTableColumn,
},
props: {
  // 生成 el-table-column
  tableCol: {
    type: Array,
    default: () => [],
  },
  // 显示的数据
  tableData: {
    type: Array,
    default: () => [],
  },
  // 表格 loading
  loading: {
    type: Boolean,
    default: false,
  },
},
computed: {
  // 兼容之前的属性
  bindTableCol() {
    function processColumn(item, device) {
      // 处理每个列对象,创建一个新对象并复制原对象属性
      let processedItem = {
        ...item,
        // 兼容之前属性
        prop: item.slot || item.key || item.type,
        label: item.label || item.title,
        // 修改默认值
        align: item.align || "center",
        fixed: device === "desktop" ? item.fixed : false,
        "show-overflow-tooltip": !(item.showOverflowTooltip === false),
        "min-width": item.minWidth || item["min-width"] || 130,
      };
      // 如果存在子列,递归处理子列
      if (item.children) {
        processedItem.children = item.children.map((child) =>
          processColumn(child, device)
        );
      }
      return processedItem;
    }
    return this.tableCol.map((item) => processColumn(item, this.device));
  },
  device() {
    return this.$store.getters.device;
  },
},
data() {
  return {
    key: Math.random(),
  };
},
methods: {
  // 双击单元格触发事件
  cellDblclick(row, column, cell, event) {
    // 避免点击过快导致多个输入框处于焦点状态
    // row[column.property + "Show"] = false;
    // 避免点击其他单元格导致表格刷新
    // if (!['address'].includes(column.property)) return
    // row[column.property + "Show"] = true;
    this.updateTable();
    this.$emit("cell-dblclick", row, column, cell, event);
  },
  // 清除 单元格选择
  resetShow(row, column) {
    setTimeout(() => {
      row[column.property + "Show"] = false;
      this.updateTable();
    }, 100);
  },
  //更新表格
  updateTable() {
    this.key = Math.random();
  },
  // 外部调用 校验方法
  verifyTable() {
    let verifyCol = this.bindTableCol.filter((e) => e.required);
    let soul = {
      state: false,
      message: "",
    };
    this.tableData.forEach((element) => {
      verifyCol.forEach((col, index) => {
        if (!element[col.slot] && element[col.slot] !== 0) {
          soul.state = true;
          soul.message =
            soul.message + `第${1 + index}行,${col.label}不能为空;`;
        }
      });
    });
    if (!this.tableData.length && verifyCol.length) {
      soul.state = true;
      soul.message = "表格未填写";
    }
    if (soul.state) {
      if (soul.message.length > 1000) {
        soul.message = soul.message.substring(0, 1000) + "......";
      }
      this.$modal.msgWarning(soul.message);
    }
    return soul.state;
  },
},
};
</script>

<style scoped></style>

2.huTableColumn.vue

<template>
<el-table-column v-if="item.show !== false" v-bind="$attrs">
 <!-- 头部 -->
 <template #header>
   <el-tooltip
     effect="dark"
     content="当前列必填"
     placement="top"
   >
     <span v-if="item.required" style="color: red">*</span>
   </el-tooltip>
   <el-tooltip
     effect="dark"
     content="当前列双击可编辑"
     placement="top"
   >
     <i v-if="item.edit" class="el-icon-edit-outline"></i>
   </el-tooltip>
   <span>
     {{ item.title }}
   </span>
 </template>
 <!-- 内容 -->
 <template v-if="item.slot" v-slot="{ row, column, $index }">
   <template v-if="item.function">
     <div v-html="item.function(row)"></div>
   </template>
   <template v-else>
     <slot
       :name="item.slot"
       :$index="$index"
       :row="row"
       :column="column"
     ></slot>
   </template>
 </template>
 <template v-if="item.children && item.children.length">
   <hu-table-column
     v-bind="e"
     v-for="e in item.children"
     :key="e.prop"
     :item="e"
     slot=""
   >
     <template v-if="e.slot" v-slot:[e.slot]="{ row, column, $index }">
       <slot
         :name="e.slot"
         :$index="$index"
         :row="row"
         :column="column"
       ></slot>
     </template>
   </hu-table-column>
 </template>
</el-table-column>
</template>

<script>
export default {
name: "huTableColumn",
props: {
 item: {
   type: Object,
   default: () => ({}),
 },
},
methods: {
},
};
</script>

<style lang="scss" scoped>
.el-icon-edit {
color: #496dff;
cursor: pointer;
&:hover {
 color: #7590fd;
}
}
</style>

注意事项:
1.嵌套表头的时候,多级表头无法使用slot插槽。
2.必须要有key或者slot或者type,并且具有唯一性。

2.使用

需要先在main.js里注册

   // 表格组件
   import HuTable from "@/components/huTable/huTable"
   Vue.component("HuTable", HuTable);

页面使用

    <hu-table
        :tableData="tableData"
        :loading="HuLoading"
        @selection-change="handleSelectionChange"
        :tableCol="tableCol"
        >
            <!-- slot插槽使用 -->
            <template v-slot:operate="{ row }">
              <el-button>按钮</el-button>
            </template>
    </hu-table>
    export default {
      data() {
        return {
        HuLoading: false,
          tableCol: [
             // 可参考elementui el-table-column属性
            {
              type: "selection", // type属性参考 el-table
              width: "55" // 设定宽度 
            },
            {
              title: "序号",
              type: "index",
              show: false, // 是否显示,默认true
            },
            {
              title: "名称",
              key: "name", 
              minWidth: 100, // 最大宽度
            },
            {
              title: "自定义内容",
              function: (item) => {
                return item; // 自定义内容 html
              },
            },
            {
              title: "操作",
              slot: "operate", 
              fixed: "right", // 是否固定left或者right,默认不固定
              width: 200,
            },
          ],
          tableData: [
            {
                name: '张三',
                age: 18
            },
            {
                name: '李四'
                age: 18
            }
          ]
        }
      }
     }