下述代码为组件实现代码复制即可食用,默认只展示 一屏数据加两条

全选存在些许问题, 使用row-key时,如果行过多滚动时会不会很流畅

特别需要注意的是 行高必须要保持一致

<template>  <div class="t-table" :id="TTableId">    <el-table      ref="el-table"      :tooltip-effect="tooltipEffect"      :data="tableData"      border      :height="height"      :row-class-name="rowClassName"      :key="tableKey"      :row-key="getRowKey"      @select-all="        val => {          this.selectAll(val, !isAll);        }      "      @select="select"      @current-change="handleCurrentChange"      :highlight-current-row="highlightCurrentRow"      :header-cell-style="headerCellStyle"      :cell-style="cellStyle"      :empty-text="emptyText"      @row-click="        (row, column, event) => this.rowClick(row, column, event, 'table')      "    >      <el-table-column type="index" v-if="index" align="center" fixed>        <template slot-scope="scope">          {{ start > 0 ? scope.$index + start + 1 : scope.$index + 1 }}        </template>      </el-table-column>      <el-table-column        type="selection"        fixed        :reserve-selection="true"        :width="$TableWidth.px46"        v-if="selection"        :selectable="rowSelectable"      ></el-table-column>      <slot></slot>    </el-table>  </div></template><script>export default {  components: {  },  name: "TTable",  props: {    //表格数据列表    saveDATA: {      typeof: Array,      default: []    },    //表格高度    height: {      typeof: Number,      default: 400    },    //一行高度 为了计算高度,需要行高固定且不能出现换行数据    itemHeight: {      typeof: Number,      default: 49    },    rowClassName: {      typeof: Function,      default: () => {}    },    tooltipEffect: {      typeof: String,      default: ""    },    //行key 必须填写saveDATA里面的变量名    rowKey: {      typeof: String,      default: ""    },    //是否显示复选框列    selection: {      typeof: Boolean,      default: false    },    //是否显示序号列    index: {      typeof: Boolean,      default: false    },    //行禁选方法    rowSelectable: {      typeof: Function,      default: () => {}    },    //是否可以单选    highlightCurrentRow: {      typeof: Boolean,      default: false    },    //表头样式    headerCellStyle: {      typeof: Object    },    //表格样式    cellStyle: {      typeof: Object    },    //无数据文字    emptyText: {      typeof: String,      default: ""    },    colDisable: {      typeof: Array    },    //组件id 如果一个页面需要使用多个ttable组件 需要给此参数赋唯一值    TTableId: {      typeof: String,      default: "t_table"    }  },  data() {    return {      tableData: [], //展示数据列表      tableRef: null, // 设置了滚动的那个盒子      tableWarp: null, // 被设置的transform元素      fixLeft: null, // 固定左侧--设置的transform元素      fixRight: null, // 固定右侧--设置的transform元素      tableFixedLeft: null, // 左侧固定列所在的盒子      tableFixedRight: null, // 右侧固定列所在的盒子      scrollTop: 0, //滚动高度      scrollNum: 0, //当前滚动了几屏数据  scrollTop / (itemHeight * pageList)      scrollRowNum: 0, //记录当前滚动了多少条数据      start: 0, //默认截取数据开始位数      end: this.pageList + 2, //默认截取数据结束位数      selectList: [], //当前选中的列表      isAll: false, //是否全选      tableKey: "", //表格key      currentRow: "", //单选数据    };  },  watch: {    //每滚动一条数据则更改展示数据源并且更改容器偏移量    scrollRowNum(newV) {      this.start = newV - 1;      this.end = this.pageList + newV + 1;      if (this.start <= 0) this.start = 0;      this.tableData = this.saveDATA.slice(this.start, this.end);      if (this.currentRow) this.setCurrentRow(this.currentRow);      requestAnimationFrame(() => {        // 计算偏移量        let translateY = `translateY(${this.start * this.itemHeight}px)`;        this.tableWarp.style.transform = translateY;        if (this.fixLeft) {          this.fixLeft.style.transform = translateY;        }        if (this.fixRight) {          this.fixRight.style.transform = translateY;        }        this.doLayout();      });    },     saveDATA: {      handler(val) {        this.init();        this.initMounted();      },      deep: true // 深度监听    },    pageList() {      this.init();      this.initMounted();    }  },  created() {  },  mounted() {    this.$nextTick(() => {      this.tableSetRef = this.GetTableRef();    });  },  methods: {    clearIndex() {      this.start = 0;      this.end = this.pageList + 2;       this.scrollNum = 0;      if (this.tableRef) this.tableRef.scrollTop = 0;    },    //初始化表格内容盒子    initMounted() {      this.$nextTick(() => {        let box = document.getElementById(this.TTableId);        // 设置了滚动的盒子        this.tableRef = this.$refs["el-table"].bodyWrapper;        // 左侧固定列所在的盒子        this.tableFixedLeft = box.querySelector(          ".el-table .el-table__fixed .el-table__fixed-body-wrapper"        );        // 右侧固定列所在的盒子        this.tableFixedRight = box.querySelector(          ".el-table .el-table__fixed-right .el-table__fixed-body-wrapper"        );        /**         * fixed-left | 主体 | fixed-right         */        // 创建内容盒子divWarpPar并且高度设置为所有数据所需要的总高度        let dwp = box.getElementsByClassName("divWarpPar")[0];        if (dwp) {          dwp.style.height = this.saveDATA.length * this.itemHeight + "px";        } else {          let divWarpPar = document.createElement("div");          divWarpPar.className = "divWarpPar";          // 如果这里还没获取到saveDATA数据就渲染会导致内容盒子高度为0,可以通过监听saveDATA的长度后再设置一次高度          divWarpPar.style.height =            this.saveDATA.length * this.itemHeight + "px";          // 新创建的盒子divWarpChild          let divWarpChild = document.createElement("div");          divWarpChild.className = "fix-warp divWarpChild";          // 把tableRef的第一个子元素移动到新创建的盒子divWarpChild中          divWarpChild.append(this.tableRef.children[0]);          // 把divWarpChild添加到divWarpPar中,最把divWarpPar添加到tableRef中          divWarpPar.append(divWarpChild);          this.tableRef.append(divWarpPar);        }        // left改造        let dlp = box.getElementsByClassName("divLeftPar")[0];        if (dlp) {          dlp.style.height = this.saveDATA.length * this.itemHeight + "px";        } else {          let divLeftPar = document.createElement("div");          divLeftPar.className = "divLeftPar";          divLeftPar.style.height =            this.saveDATA.length * this.itemHeight + "px";          let divLeftChild = document.createElement("div");          divLeftChild.className = "fix-left";          this.tableFixedLeft &&            divLeftChild.append(this.tableFixedLeft.children[0]);          divLeftPar.append(divLeftChild);          this.tableFixedLeft && this.tableFixedLeft.append(divLeftPar);        }        // right改造        let drp = box.getElementsByClassName("divRightPar")[0];        if (drp) {          drp.style.height = this.saveDATA.length * this.itemHeight + "px";        } else {          let divRightPar = document.createElement("div");          divRightPar.className = "divRightPar";          divRightPar.style.height =            this.saveDATA.length * this.itemHeight + "px";          let divRightChild = document.createElement("div");          divRightChild.className = "fix-right";          this.tableFixedRight &&            divRightChild.append(this.tableFixedRight.children[0]);          divRightPar.append(divRightChild);          this.tableFixedRight && this.tableFixedRight.append(divRightPar);        }        // 被设置的transform元素        this.tableWarp = box.querySelector(          ".el-table .el-table__body-wrapper .fix-warp"        );        this.fixLeft = box.querySelector(          ".el-table .el-table__fixed .el-table__fixed-body-wrapper .fix-left"        );        this.fixRight = box.querySelector(          ".el-table .el-table__fixed-right .el-table__fixed-body-wrapper .fix-right"        );        this.tableRef.addEventListener("scroll", this.onScroll);      });    },    // 初始化数据    init() {      this.clearIndex();      this.tableData = this.saveDATA.slice(this.start, this.end);    },    // 滚动事件    onScroll() {      //解决固定行 与 非固定行 滚动时错位问题      let body = document.getElementById(this.TTableId);      let fixedBox = body.getElementsByClassName(        "el-table__fixed-body-wrapper"      );      if (fixedBox) {        for (let i = 0; i < fixedBox.length; i++) {          const element = fixedBox[i];          element.scrollTop = this.tableRef.scrollTop;        }      }      //,      this.scrollTop = this.tableRef.scrollTop; //获取顶部距离      this.scrollNum =        Math.floor(this.scrollTop / (this.itemHeight * this.pageList)) + 1; //计算滚动到几屏数据      this.scrollRowNum = Math.ceil(this.scrollTop / this.itemHeight); //计算已经滚动了多少条数据      //移除掉滚动时遗留的hover-row      if (this.GetTableRef()) {        const elements = body.getElementsByClassName(          "hover-row"        );        for (let i = 0; i < elements.length; i++) {          elements[i].classList.remove("hover-row");        }      }    },    //获取表格ref    GetTableRef() {      return this.$refs["el-table"];    },    //刷新表格key    RefreshTableKey() {      this.tableKey = this.$common.GetNextStr();      this.clearIndex();      this.initMounted();    },    //设置行key    getRowKey(row) {      return this.$common.GetValueByPath(row, this.rowKey);    },    //单行选择触发事件    select(val) {      this.selectList = val;      this.$emit("selection-change", val);    },    //全选触发事件    selectAll(val, isAll) {      this.isAll = isAll;      if (isAll) {        let list = JSON.parse(JSON.stringify(this.saveDATA));        if (this.rowSelectable)          this.selectList = list.filter((m, i) => this.rowSelectable(m, i));        else this.selectList = list;        let dList = this.selectList.filter(          m => val.findIndex(k => JSON.stringify(k) == JSON.stringify(m)) == -1        );        dList.forEach(row => {          this.GetTableRef().toggleRowSelection(row);        });      } else {        this.clearSelection();      }      this.$emit("selection-change", this.selectList);    },    //清空表格    clearSelection() {      this.GetTableRef().clearSelection();      this.selectList = [];      this.$emit("selection-change", this.selectList);    },    //单行选中触发事件    handleCurrentChange(val) {      this.currentRow = val;      this.$emit("current-change", val);    },    //设置指定行为单行选中    setCurrentRow(row) {      this.currentRow = row;      this.GetTableRef().setCurrentRow(row);    },    rowClick(row, column, event) {      this.$emit("row-click", row, column, event);    },    //重新布局表格    doLayout() {      this.GetTableRef().doLayout();    },  },  computed: {    pageList() {      return Math.ceil(this.height / this.itemHeight);    }  }};</script><style>.t-table .el-table__body-wrapper {  overflow: auto !important;  background-blend-mode: overlay !important;}</style>

下面为调用示例

<template>  <div class="t-table" id="t_table">    <TTable :saveDATA="saveDATA" :height="200">      <el-table-column fixed label="id" prop="id"></el-table-column>      <el-table-column  fixed label="姓名" prop="name"></el-table-column>      <el-table-column label="年龄" prop="age"></el-table-column>      <el-table-column        label="地址"        prop="address"        min-width="300"      ></el-table-column>      <el-table-column        label="地址"        prop="address"        min-width="300"      ></el-table-column>      <el-table-column        label="地址"        prop="address"        min-width="300"      ></el-table-column>      <el-table-column        label="地址"        prop="address"        min-width="300"      ></el-table-column>      <el-table-column        label="地址"        prop="address"        min-width="300"      ></el-table-column>      <el-table-column        label="地址"        prop="address"      min-width="300"      ></el-table-column>    </TTable>  </div></template><script>import TTable from "../../../src/components/TTable.vue";export default {  components: {    TTable,  },  props: {},  data() {    return {      saveDATA: [], // 所有数据    };  },  watch: {},  created() {  },  mounted() {    this.init();  },  methods: {    init() {      this.saveDATA = [];      for (let i = 0; i < 2000; i++) {        this.saveDATA.push({          id: i,          name: `张三${i}`,          age: i,          address: "重庆市渝中区两路口阿士大夫撒多富士达浪费的水立方as的裂缝阿萨德立法技术放两三分啥地方了as的裂缝as了巅峰就啥的立法啥的立法阿斯蒂芬了as的裂缝就啥砥砺奋进阿萨德理发店发了"        });      }    }  }};</script>