vue make tableコンポーネント


以前に作成されたコンポーネントであり続け、感謝します

<template>
  <div class="FitTable" :style="tableStyle">
    <div class="FitTable-header" ref="header" :style="{width:tbodyWidth + 'px', backgroundColor: backgroundColor}">
      <div class="FitTable-header__content">
        <div v-for="(item, index) in columns" :key="item.unique || index" class="FitTable-cell"
             :style="{minWidth: typeof item.minWidth === 'number'?item.minWidth + 'px':item.minWidth,
             width: item.width + 'px',
             textAlign: item.textAlign || 'center',
             height: headerHeight + 'px'}"
             :title="item.title">
          <slot :name="item.slotHeader" :data="{...item,index}">
            <div style="margin: 1px 5px;color: #DBE5E8;">{{item.title}}</div>
          </slot>
        </div>
      </div>
    </div>
    <div :style="tbodyHeight" ref="tableTbody">
      <FitScroll>
        <div class="FitTable-body">
          <div class="FitTable-body-row">
            <div class="FitTable-body-row_line" v-for="(item,index) in data" :key="(dataKey && item[dataKey]) || index" :style="{height: lineHeight}">
                <div v-for="(_item, _index) in columns" :key="_item.unique || _index" class="FitTable-cell"
                     :style="{minWidth: typeof _item.minWidth === 'number'?_item.minWidth + 'px':_item.minWidth,
                     width: _item.width + 'px',
                     textAlign: _item.textAlign || 'center'}">
                  <div class="FitTable-cell-content">
                    <div  class="FitTable-cell-content-data">
                      <slot :name="_item.slot" :data="{...item,index}">
                        <span :title="item[_item.key]" style="color: #DBE5E8;">
                          {{item[_item.key]}}
                        </span>
                      </slot>
                    </div>
                  </div>
                </div>
            </div>
          </div>
        </div>
      </FitScroll>
    </div>
  </div>
</template>

<script>
 /* eslint-disable */
export default {
  name: "FitTable",
  props: {
    maxHeight: {
      type: String,
      default: null
    },
    // 表格宽度,默认100%
    width: {
      type: String,
      default: '100%'
    },
    height: {
      type: Number | String,
      default: '100%'
    },
    // 起始索引
    // startIndex:{
    //   type: Number,
    //   default: 0
    // },
    /* TODO columns接受值: 对象数组
        title: 表头名称
        slotHeader: 表头插槽名称
        slot: 表体插槽
        unique: 默认索引值,必须唯一,便于vue优化
        key: 对应prop:{data}中数据的键值
        minWidth: 对应列最小宽度
    */
    columns: {
      type: Array,
      default: () => []
    },
    data: {
      type: Array,
      default: () => []
    },
    headerHeight: {
      type: Number,
      default: 35
    },
    backgroundColor: {
      type: String,
      // default: '#3c6180',
      default: 'rgba(60,97,128,0.3)'
    },
    lineHeight: {
      type: String,
      default: ''
    },
    // prop:{data}中唯一的值,不传则通过索引优化表格
    dataKey: {
      type: String,
      default: null
    }
  },
  computed: {
    tableStyle: {
      get () {
        return {width: this.width,maxHeight: this.maxHeight,height:typeof this.height === 'number' ?this.height + 'px':'100%'};
      }
    },
    tbodyHeight () {
      const height = this.tableHeight > (this.maxHeight || Infinity)?this.maxHeight:this.tableHeight;
      return { height: height -this.headerHeight + 'px',overflowY: 'auto' };
    }
  },
  watch: {
    height () {
      if (String(this.height).indexOf('%') !== -1) {
        this.tableHeight = this.$el.offsetHeight * parseInt(this.height) / 100
      } else {
        this.tableHeight = this.height;
      }
    }
  },
  data: () => ({
    rowWidth: null,
    // 将自定义的列width值收集起来的和
    customWidth: { count: 0, value: 0 },
    tbodyWidth: 0,
    tableHeight: 0,
    theaderHeight: 0
  }),
  mounted() {
      // const width = this.$el.offsetWidth;
      // this.theaderHeight = this.$refs['header'].offsetHeight;
    this.$nextTick(() => {
      if (String(this.height).indexOf('%') !== -1) {
        this.tableHeight = this.$el.offsetHeight * parseInt(this.height) / 100;
      } else {
        this.tableHeight = this.height;
      }
      this.tbodyWidth = this.$refs['tableTbody'].clientWidth;
      // console.log(this.$el.offsetHeight, this.tableHeight, 777)
    });
      // this.rowWidth = (width - this.customWidth.value) / (this.columns.length - this.customWidth.count) + 'px';
      // // eslint-disable-next-line no-console
      window.addEventListener('resize', this.refreshTableRow);
  },
  beforeDestroy () {
    window.removeEventListener('resize', this.refreshTableRow);
  },
  methods: {
    refreshTableRow() {
      // if (this.width.indexOf('%') !== -1) {
      //   const width = this.$el.offsetWidth;
      //   this.rowWidth = (width - this.customWidth.value) / (this.columns.length - this.customWidth.count) + 'px'
      // }
      this.theaderHeight = this.$refs['header'].offsetHeight;
      if (String(this.height).indexOf('%') !== -1) {
        this.tableHeight = this.$el.offsetHeight * parseInt(this.height) / 100
      }
      this.tbodyWidth = this.$refs['tableTbody'].clientWidth;
    }
  }
}
</script>

<style lang="scss" scoped>
  @import "../../styles/_scroll";
  .FitTable {
    position: relative;
    &-header {
      display: table;
      table-layout: fixed;
      box-sizing: border-box;
      // border-bottom: 1px solid rgba(255,255,255,0.32);
      &__content {
        display: table-header-group;
        .FitTable-cell {
          display: table-cell;
          vertical-align: middle;
          > div {
            //position: relative;
            //top: 50%;
            //transform: translateY(-50%);
            overflow: hidden;
            white-space: nowrap;
            text-overflow: ellipsis;
          }
        }
      }
    }
    &-body {
      width: 100%;
      display: table;
      box-sizing: border-box;
      table-layout: fixed;
      &-row {
        display: table-row-group;
        &_line {
          display: table-row;
          &:nth-child(odd) {
            background-color: transparent;
          }
          &:nth-child(even) {
            background-color: rgba(158,158,158,0.1);
          }
          .FitTable-cell {
            display: table-cell;
            vertical-align: middle;
            &-content {
              height: 30px;
              margin: 1px 5px;
              &-data {
                position:relative;
                top: 15px;
                transform: translateY(-50%);
                overflow: hidden;
                white-space: nowrap;
                text-overflow: ellipsis;
              }
            }
          }
        }
      }
    }
  }
</style>

おすすめ

転載: www.cnblogs.com/smallZoro/p/12722344.html