超级表格组件之render抽象

参考——element el-table表格的vue组件二次封装(附表格高度自适应) - 掘金 (juejin.cn)

JSX——Vue JSX、自定义 v-model - 你的美好,我都记得 (ainyi.com)

0.问题

抽象一个复杂表格组件

1.解决方法

借助element自己的renderHeader与上面的大佬写的render函数,可以抽象出来这样一个组件

// tableCom.vue

<template>
  <div>
    <el-table
      empty-text="暂无数据"
      ref="table"
      :data="tableList"
      border
      stripe
      fit
      highlight-current-row
      :height="inTableHeight"
      @selection-change="selectionChange"
      @row-click="rowClick"
      :header-cell-style="{ background: 'rgb(1, 97, 90)', color: 'white' }"
    >
      <!-- 选择框 -->
      <el-table-column
        v-if="select"
        type="selection"
        fixed="left"
        width="55"
        align="center"
      />
      <template v-for="(itm, idx) in header">
        <!-- 特殊处理列 -->
        <el-table-column
          v-if="itm.render && !itm.children"
          :key="idx"
          :renderHeader="itm.renderHeader ? itm.renderHeader : null"
          :prop="itm.prop ? itm.prop : null"
          :label="itm.label ? itm.label : null"
          :width="itm.width ? itm.width : null"
          :sortable="itm.sortable ? itm.sortable : false"
          :align="itm.align ? itm.align : 'center'"
          :fixed="itm.fixed ? itm.fixed : null"
          :show-overflow-tooltip="itm.tooltip"
          min-width="50"
        >
          <template slot-scope="scope">
            <ex-slot
              :render="itm.render"
              :row="scope.row"
              :index="scope.$index"
              :column="itm"
            />
          </template>
        </el-table-column>
        <!-- 二级表头 -->
        <el-table-column
          :key="idx"
          v-if="itm.children"
          :label="itm.label ? itm.label : null"
          header-align="center"
          :renderHeader="itm.renderHeader ? itm.renderHeader : null"
        >
          <el-table-column
            v-for="(child, indexNum) in itm.children"
            :key="indexNum"
            :renderHeader="child.renderHeader ? child.renderHeader : null"
            :prop="child.prop ? child.prop : null"
            :label="child.label ? child.label : null"
            :width="child.width ? child.width : null"
            :sortable="child.sortable ? child.sortable : false"
            :align="child.align ? child.align : 'center'"
            :fixed="child.fixed ? child.fixed : null"
            :show-overflow-tooltip="child.tooltip"
            min-width="50"
          >
            <template slot-scope="scope">
              <ex-slot
                :render="child.render"
                :row="scope.row"
                :index="scope.$index"
                :column="child"
              />
            </template>
          </el-table-column>
        </el-table-column>
        <!-- 正常列 -->
        <el-table-column
          v-if="!itm.render && !itm.children"
          :key="idx"
          :renderHeader="itm.renderHeader ? itm.renderHeader : null"
          :prop="itm.prop ? itm.prop : null"
          :label="itm.label ? itm.label : null"
          :width="itm.width ? itm.width : null"
          :sortable="itm.sortable ? itm.sortable : false"
          :align="itm.align ? itm.align : 'center'"
          :fixed="itm.fixed ? itm.fixed : null"
          :formatter="itm.formatter"
          :show-overflow-tooltip="itm.tooltip"
          min-width="50"
        />
      </template>
    </el-table>
  </div>
</template>

<script>
// 自定义内容的组件
var exSlot = {
  functional: true,
  props: {
    row: Object,
    render: Function,
    index: Number,
    column: {
      type: Object,
      default: null,
    },
  },
  render: (h, context) => {
    const params = {
      row: context.props.row,
      index: context.props.index,
    };
    if (context.props.column) params.column = context.props.column;
    return context.props.render(h, params);
  },
};

export default {
  components: { exSlot },
  props: {
    tableList: {
      type: Array,
      default: () => [],
    },
    header: {
      type: Array,
      default: () => [],
    },
    select: {
      type: Boolean,
      default: () => false,
    },
    height: {
      type: [Number, String, Function],
      default: () => null,
    },
  },
  data() {
    return {
      inTableHeight: null,
    };
  },
  created() {
    //该阶段可以接收父组件的传递参数
    this.inTableHeight = this.height;
    console.log("slot see", this.$slots); // 看看里面有啥
  },
  mounted() {
    this.$nextTick(() => {
      //表格高度自适应浏览器大小
      this.changeTableHight();
      if (!this.height) {
        window.onresize = () => {
          this.changeTableHight();
        };
      }
    });
  },
  destroyed() {
    //高度自适应事件注销
    window.onresize = null;
  },
  watch: {
    /**
     * 数据变化后 高度自适应
     */
    tableList() {
      this.$nextTick(() => {
        this.changeTableHight();
      });
    },
  },
  methods: {
    /**
     * 选择框选择后更改,事件分发
     */
    selectionChange(selection) {
      this.$emit("selection-change", selection);
    },
    /**
     * 点击事件
     */
    rowClick(row, column, event) {
      this.$emit("row-click", row, column, event);
    },
    /**
     * 高度自适应
     * 当表格展示空间小于460按460px展示,大于的时候高度填充
     */
    changeTableHight() {
      if (this.height) {
        //如果有传进来高度就取消自适应
        this.inTableHeight = this.height;
        this.$refs.table.doLayout();
        return;
      }
      let tableHeight = window.innerHeight || document.body.clientHeight;
      //高度设置
      let disTop = this.$refs.table.$el;
      //如果表格上方有元素则减去这些高度适应窗口,66是底下留白部分
      tableHeight -= disTop.offsetTop + 26;
      if (disTop.offsetParent) tableHeight -= disTop.offsetParent.offsetTop;
      this.inTableHeight = tableHeight < 460 ? 460 : tableHeight;
      //重绘表格
      this.$refs.table.doLayout();
    },
  },
};
</script>
<style>
.changeColorYellow {
  color: rgb(206, 206, 169);
}
</style>
View Code

2.使用

// testPage.vue

普通表格内容的使用

二级表头使用

 3.补充——其他版本的render抽象

上代码

// lineCom.vue

<template>
  <div class="lineCom">
    <template v-for="(itm, idx) in header">
      <div v-if="itm.render" :key="idx">
          <ex-slot
            :render="itm.render"
            :column="itm"
          />
      </div>
    </template>
  </div>
</template>

<script>
// 自定义内容的组件
var exSlot = {
  functional: true,
  props: {
    row: Object,
    render: Function,
    index: Number,
    column: {
      type: Object,
      default: null,
    },
  },
  render: (h, context) => {
    // const params = {
    //   row: context.props.row,
    //   index: context.props.index,
    // };
    // if (context.props.column) params.column = context.props.column;
    return context.props.render(h, context.props.column);
  },
};

export default {
  components: { exSlot },
  props: {
    header: {
      type: Array,
      default: () => [],
    },
  },
};
</script>
View Code

// lineComTable.js

// 使用

人生到处知何似,应似飞鸿踏雪泥。
原文地址:https://www.cnblogs.com/lepanyou/p/15384942.html