使用函数式组建封装elment的table,优雅地调用配置文件即可

141 阅读1分钟

1.先看效果

export const tableColumns = function () {
  return [
    {
      type: 'selection', //多选选中框
    },
    {
      label: '广告图片',
      prop: 'img',
      width: '200',
      previewImage: true, //使用imageview
      render: (h, { row }) => <img src={row.img} style="width: 171.5px; height: 80px;" />,
    },
    {
      label: '排序',
      prop: 'rank',
      sortable: true, //排序
    },
    {
      label: '操作',
      prop: 'operation',
      width: '150',
      align: 'center',
      headerAlign: 'center',
      render: (h, { row, index }) => {
        return (
          <div>
            123
          </div>
        );
      },
    },
  ];
};

看起来是不是非常简单呢 !

2.源码在这里

  1. columns 传入配置数组
  2. image-viewer 是图片预览插件,方便表格中的图片中的图片预览
<template>
  <div :style="style">
    <!-- row-key="id" 优化Table渲染 -->
    <el-table
      :data="data"
      size="medium"
      v-loading="loading"
      fit
      :header-cell-style="headerCellStyle"
      :row-style="rowStyle"
      :max-height="data && data.length >= 1 ? maxHeight : 'null'"
      ref="multipleTable"
      :height="styleHeight"
      :border="border"
      stripe
      :row-key="rowKey"
      :default-sort="sort"
      :default-expand-all="expandAll"
      @sort-change="handleSort"
      @filter-change="filterHandler"
      @row-click="handleRowClick"
      @selection-change="handleSelectionChange"
      @select="handleSelect"
      @select-all="handleSelectAll"
      @expand-change="handleExpandChange"
    >
      <el-table-column
        v-for="(th, key) in columns"
        :key="key"
        :prop="th.prop"
        :label="th.label"
        :fixed="th.fixed"
        :sortable="th.sortable ? th.sortable : false"
        :filters="th.filters"
        :column-key="th.columnKey"
        :filtered-value="th.filteredValue"
        :filter-multiple="th.filterMultiple"
        :min-width="th.minWidth"
        :width="th.width"
        :type="th.type"
        :align="th.align || 'center'"
        :header-align="th.headerAlign || th.align"
        :preview-image="th.previewImage"
        :selectable="th.selectable"
      >
        <template v-if="!th.type" v-slot="{ row, column, $index }">
          <!-- 普通情况 -->
          <ex-slot v-if="th.render && !th.previewImage" :render="th.render" :row="row" :index="$index" :column="th" />
          <!-- 带图片的插槽 -->
          <div v-else-if="th.previewImage" @click="handleImageViewer(th.prop, row, $index)" class="pointer">
            <ex-slot :render="th.render" :row="row" :index="$index" :column="th" />
          </div>
          <!-- 其他 -->
          <span v-else>{{ row[th.prop] === null || row[th.prop] === 'null' ? '-' : row[th.prop] }}</span>
        </template>
        <template v-else-if="th.type === 'expand'" v-slot="{ row, column, $index }">
          <ex-slot v-if="th.render" :render="th.render" :row="row" :index="$index" :column="th" />
        </template>
      </el-table-column>
    </el-table>
    <!-- 分页 -->
    <Page
      v-if="paginated"
      :total="total"
      :current-page="currentPage"
      @size-change="handleSizeChange"
      @current-page="handleCurrentChange"
    />

    <!-- 图片预览 -->
    <image-viewer ref="imageViewer" :images="images" />
  </div>
</template>

<script>
import Page from '@/components/Page';
import ImageViewer from '@/components/ImageViewer';
import { parsePx } from '@/utils/index';

// 自定义内容的组件
const exSlot = {
  functional: true,
  props: {
    row: Object,
    render: Function,
    index: Number,
    column: {
      type: Object,
      default: null,
    },
  },
  render: (h, { props }) => {
    //row index column 继续向下传值
    const params = {
      row: props.row,
      index: props.index,
    };
    if (props.column) params.column = props.column;
    return props.render(h, params);
  },
};

export default {
  components: { exSlot, Page, ImageViewer },
  props: {
    sort: {
      type: Object,
    },
    border: {
      type: Boolean,
      default: true,
    },
    expandAll: {
      type: Boolean,
      default: false,
    },
    // 是否开启分页
    paginated: {
      type: Boolean,
      default: true,
    },
    //分页的总条数
    total: {
      type: Number,
      default: 0,
    },
    // 表格数据
    data: {
      type: Array,
      default: function () {
        return [];
      },
    },
    rowKey: {
      type: String,
      default: '',
    },
    // 表头数据
    columns: {
      type: Array,
      default: function () {
        return [];
      },
    },
    loading: {
      type: Boolean,
      default: false,
    },
    maxHeight: {
      type: [String, Number],
      default: 'null',
    },
    //默认值一定记得给null 否则报错
    height: {
      type: [String, Number],
      default: null,
    },
    pageSize: {
      type: Number,
    },
    currentPage: {
      type: Number,
      default: 1,
    },
    //翻页是否返回顶部
    backTop: {
      type: Boolean,
      default: true,
    },
  },
  computed: {
    styleHeight() {
      return parsePx(this.height);
    },
    style() {
      return {
        height: this.paginated ? 'calc(100% - 132px)' : '100%',
      };
    },
  },
  data() {
    return {
      images: '',
      //自定义每行的样式
      rowStyle: {},
      //自定义头部的样式
      headerCellStyle: {},
    };
  },
  methods: {
    /**
     * prop 当前列 row: 当前行数据 index: 当前的数据索引
     * 图片预览
     * */
    handleImageViewer(prop, row, index) {
      this.images = row[prop];
      this.$refs.imageViewer.show();
    },
    //当选择项发生变化时会触发该事件
    handleSelectionChange(selection) {
      this.$emit('selection-change', selection);
    },
    //单选
    handleSelect(selection, row) {
      this.$emit('select', selection, row);
    },
    //全选
    handleSelectAll(selection) {
      this.$emit('select-all', selection);
    },
    // 排序事件
    handleSort(sort) {
      this.$emit('sort-change', sort);
    },
    // 筛选事件
    filterHandler(filters) {
      this.$emit('filter-change', filters);
    },
    // 某一行被点击
    handleRowClick(row, column, event) {
      this.$emit('row-click', { row, column, event });
    },
    //修改分页
    handleSizeChange(v) {
      this.$emit('update:pageSize', v);
      this.$emit('size-change', v);
      //修改分页回到第一页
      this.handleCurrentChange(1);
    },
    //改变当前页
    handleCurrentChange(v) {
      this.$emit('update:currentPage', v);
      this.$emit('current-page', v);
      if (this.backTop) {
        this.scrollTop();
      }
    },
    // 展开列被点击时
    handleExpandChange(row, expand) {
      this.$emit('expand-change', { row, expand });
    },
    //翻页返回顶部
    scrollTop() {
      let overflowY = this.$el.getElementsByClassName('el-table__body-wrapper')[0];
      if (!overflowY) {
        return;
      }
      overflowY.scrollTop = 0;
    },
  },
};
</script>

<style lang="scss" scoped>
.content {
  padding: 20px;
}
.pointer {
  cursor: pointer;
}
.tableHeight {
  height: 400px;
}
</style>

@