封装el-table核心代码

329 阅读2分钟

问题背景

封装el-table的时候有时候忘记语法了,然后问ai或者百度又出来一堆不太正确的回答,作此记录。

1.封装好的组件完整代码(基础版)

<template>
  <div>
    <el-table
      :data="tableData"
      :height="height"
      style="width: 100%"
      header-cell-class-name="my_headercell_class"
      cell-class-name="my_cell_class"
    >
      <el-table-column
        v-for="(column, index1) in tableHeaderList"
        :prop="column.prop"
        :label="column.label"
        :type="column.type"
        :width="column.width"
        :key="index1"
      >
        <template slot-scope="{row,$index}">
          <!-- 在这里使用 scope.row 和 scope.column 来访问行数据和列配置 -->
          <div
            class="item"
            v-if="!column.slot"
          >
            <!-- {{ column.render ? column.render(row) : row[column.prop] || '--' }} -->
            {{ column.render ? column.render(row) : getNestedProperty(row, column.prop)}}
          </div>
          <slot
            :name="column.slot"
            :row="row"
            :index="$index"
          ></slot>
        </template>
      </el-table-column>
    </el-table>
  </div>
</template>

<script>
import _ from 'lodash'
export default {
  props: {
    tableData: {
      type: Array,
      default: () => []
    },
    tableHeaderList: {
      type: Array,
      default: () => []
    },
    height: {
      type: String
    }
  },
  methods: {
    // 在 methods 中使用 _.get 来替代 getNestedProperty
    getNestedProperty(object, path) {
      return _.get(object, path, '')
    }
  }
}
</script>

<style lang="less">
.my_cell_class{
    .cell{
        overflow: visible !important;
        padding-left: 0;
    }
}
.my_headercell_class{
  .cell{
        padding-left: 0;
    }
}
</style>

2.使用

只需要传入tableHeaderList和tableData即可

<template>
  <div class="home">
    <Table :tableData="tableData" :tableHeaderList="tableHeaderList">
      <template slot="rank" slot-scope="{index}">
        <div class="rank_top_box">
          <span class="rank_number">
            {{ index + 1 }}
          </span>
          <div class="top_bg" :class="'top_bg' + index" v-if="index < 3">
            <img class="top_img" :src="require(`@/assets/mass/top_${index + 1}.png`)" alt="">
          </div>
        </div>
      </template>
    </Table>
  </div>
</template>

<script>
// @ is an alias to /src
import Table from '@/components/Table.vue';
import tableData from './tabledata'

export default {
  name: 'HomeView',
  computed: {
  },
  data() {
    return {
      tableHeaderList: [
        {
          prop: 'rank',
          label: '账号调用排行(TOP10)',
          slot: 'rank',
        },
        {
          prop: 'name',
          label: '账号名称',
        },
        {
          prop: 'apikey_count',
          label: '密钥数',
        },
        {
          prop: 'tenant.name',
          label: '所属租户',
        },
        {
          prop: 'project_count',
          label: '分配项目数',
        },
        {
          prop: 'req_count',
          label: '调用次数',
          render: (item) => {
            return item.req_count.toLocaleString()
          }
        }
      ],
      tableData: tableData,
    }
  },
  created() {
  },
  methods: {
  },
  components: {
    Table
  }
};
</script>
<style lang="less" scoped>
.home {
  .rank_top_box {
    width: 100%;
    height: 100%;
    overflow: visible;
    position: relative;
    text-align: center;

    .rank_number {
      text-align: center;
    }

    .top_bg {
      position: absolute;
      top: 0;
      left: 0;
      width: 160px;
      height: 48px;
      top: -11px;

      .top_img {
        width: 28px;
        height: 40px;
        position: absolute;
        top: 50%;
        left: 0;
        margin-top: -20px;
      }
    }

    .top_bg0 {
      background: linear-gradient(90deg, rgba(255, 59, 59, 0.35) 0%, rgba(255, 59, 59, 0) 100%);
    }

    .top_bg1 {
      background: linear-gradient(90deg, rgba(255, 140, 59, 0.35) 0%, rgba(255, 183, 59, 0) 100%);
    }

    .top_bg2 {
      background: linear-gradient(90deg, rgba(255, 216, 59, 0.35) 0%, rgba(255, 245, 59, 0) 100%);
    }
  }
}
</style>

3.效果

image.png

4.核心代码:

<el-table-column
  v-for="(column, index1) in tableHeaderList"
  :prop="column.prop"
  :label="column.label"
  :type="column.type"
  :width="column.width"
  :key="index1"
>
  <template slot-scope="{row,$index}">
    <!-- 在这里使用 scope.row 和 scope.column 来访问行数据和列配置 -->
    <div
      class="item"
      v-if="!column.slot"
    >
      <!-- {{ column.render ? column.render(row) : row[column.prop] || '--' }} -->
      {{ column.render ? column.render(row) : getNestedProperty(row, column.prop)}}
    </div>
    <slot
      :name="column.slot"
      :row="row"
      :index="$index"
    ></slot>
  </template>
</el-table-column>

5.核心解析:

1.一定要在el-table-column中去遍历传进来的tableHeaderList,不要在el-table-column外层加一个div来遍历。

2.最重要的重点是,区分slot,如果外面不需要使用slot,则直接展示值,先要去判断有没有render函数(因为数据可能要经过处理才能展示在table上),如果有render函数,则展示render函数的返回值

3.如果没有render函数,那么就使用getNestedProperty来解析深层次的对象(比如我要展示租户,需要取得值是tenant对象下面name的属性值,所以用到这个方法来解析)

4.如果不需要slot,则使用作用域插槽来将数据传递回父组件,让父组件中的插槽进行使用

6.结语

这里仅仅只是写了一个最简单的封装,主要是把封装的核心代码分享出来的,其他的需要什么配置可以自己加哈

7.代码地址

github地址: github.com/rui-rui-an/…