基于element-ui el-table 开发虚拟列表

2020-06-22 15:47:30 浏览数 (1)

普通列表

主要方法:calcList

代码语言:javascript复制
<template>
  <div id="app">
    <!-- :expand-row-keys="currentExpend" -->
    <!--        <div style="height: 800px"></div>-->
    <el-form ref="form" :model="form" label-width="80px" :rules="rules">
      <el-form-item label-width="0" prop="rows">
        <el-table
          :data="virtualRows"
          id="table"
          style="width: 100%;margin-bottom: 20px;"
          border
          row-key="customIndex"
          default-expand-all
          ref="table"
          max-height="500px"
          class="vtable"
          @expand-change="calcBottom"
          :tree-props="{children: 'children'}"
        >
          <el-table-column
            prop="customIndex"
            fixed
            label="序号"
            sortable
            width="180"
            v-slot="{$index, row}"
          >{{row.customIndex}}</el-table-column>
          <el-table-column prop="date" label="日期" sortable width="180"></el-table-column>
          <el-table-column prop="name" label="姓名" sortable width="180">
            <template v-slot="{$index, row}">
              <!-- {{`rows${getPathByKey(row.customIndex,"customIndex",form.rows)}.name`}} -->
              <el-form-item
                label-width="0"
                :rules="rules.name"
                :prop="`${row.customIndex!=='tempIndex'?`rows.${row.path}.name`:''}`"
              >
                <el-input v-model="row.name"></el-input>
              </el-form-item>
            </template>
          </el-table-column>
          <el-table-column prop="address" label="地址">
            <template v-slot="{$index, row}">
              <!-- {{`rows${getPathByKey(row.customIndex,"customIndex",form.rows)}.name`}} -->
              <el-form-item
                label-width="0"
                :rules="rules.address"
                :prop="`${row.customIndex!=='tempIndex'?`rows.${row.path}.address`:''}`"
              >
                <el-input v-model="row.address"></el-input>
              </el-form-item>
            </template>
          </el-table-column>
          <el-table-column prop="address" label="地址">
            <template v-slot="{$index, row}">
              <!-- {{`rows${getPathByKey(row.customIndex,"customIndex",form.rows)}.name`}} -->
              <el-form-item
                label-width="0"
                :rules="rules.address"
                :prop="`${row.customIndex!=='tempIndex'?`rows.${row.path}.address`:''}`"
              >
                <el-input v-model="row.address"></el-input>
              </el-form-item>
            </template>
          </el-table-column>
          <el-table-column prop="address" label="地址">
            <template v-slot="{$index, row}">
              <!-- {{`rows${getPathByKey(row.customIndex,"customIndex",form.rows)}.name`}} -->
              <el-form-item
                label-width="0"
                :rules="rules.address"
                :prop="`${row.customIndex!=='tempIndex'?`rows.${row.path}.address`:''}`"
              >
                <el-input v-model="row.address" type="text"></el-input>
              </el-form-item>
            </template>
          </el-table-column>
          <el-table-column prop="address" label="删除" width="200px" fixed="right">
            <template slot-scope="scope">
              <el-button @click="add(form.rows,scope.row.customIndex)">add</el-button>
              <el-button @click="handleDelete(form.rows,scope.row.customIndex)">delete</el-button>
            </template>
          </el-table-column>
        </el-table>
      </el-form-item>
    </el-form>
    <el-button @click="print">print</el-button>
    <el-button class="outLogin" icon="el-icon-switch-button" circle type="info"></el-button>
    <div style="height: 500px"></div>
  </div>
</template>

<script>
import _ from "lodash";
export default {
  data() {
    return {
      form: {
        rows: []
      },
      rules: {
        name: [{ required: true, message: "请输入名称", trigger: "blur" }],
        address: [{ required: true, message: "请输入地址", trigger: "blur" }]
      },
      positionType: true,
      startIndex: 0,
      viewRows: [],
      virtualRows: [],
      scrollTop: 0,
      currentExpend: ["1"]
    };
  },
  methods: {
    print() {
      // console.log(this.form.rows);
      // this.$refs.form.validate((valid, err) => {
      //   console.log("valid", valid, err);
      // });
      console.log(this.$refs);
    },
    handleDelete(arr, r) {
      for (let i = 0; i < arr.length; i  ) {
        if (arr[i].customIndex == r) {
          arr.splice(i, 1);
          return;
        }
        if (arr[i].children && arr[i].children.length > 0) {
          this.handleDelete(arr[i].children, r);
        }
      }
    },
    add(arr, r) {
      // console.log("r", arr, r)
      for (let i = 0; i < arr.length; i  ) {
        if (arr[i].customIndex == r) {
          // console.log("arr", arr)
          arr.splice(i   1, 0, { name: "666", customIndex: "tempIndex" });
          return;
        }
        if (arr[i].children && arr[i].children.length > 0) {
          this.add(arr[i].children, r);
        }
      }
    },
    setIndex(data) {
      let queue = [...data];
      let loop = 0;
      this.num = 0;
      while (queue.length > 0) {
        loop  ;
        [...queue].forEach((child, i) => {
          queue.shift();
          this.num  ;
          if (loop == 1) {
            child.customIndex = i   1   "";
            child.currentIndex = i;
            child.path = i;
          }
          if (child.children && child.children.length > 0) {
            child.dataType = 1;
            for (let ci = 0; ci < child.children.length; ci  ) {
              child.children[ci].currentIndex = ci;
              child.children[ci].customIndex =
                child.customIndex   "."   (ci   1);
              child.children[ci].path = child.path   ".children."   ci;
            }
            queue.push(...child.children);
          } else {
            child.dataType = 2;
          }
          child.expend = child.expend || true;
        });
      }
      this.$nextTick(() => {
        this.calcList();
      });
    },
    getPathByKey(value, key, arr) {
      let temppath = [];
      let realPath = "";
      try {
        function getNodePath(node) {
          temppath.push(node.currentIndex);
          //找到符合条件的节点,通过throw终止掉递归
          if (node[key] === value) {
            temppath.forEach((v, i) => {
              if (i == 0) {
                realPath  = "."   v;
              } else {
                realPath  = `.children.${v}`;
              }
            });
            // temppath = temppath.join(",")
            throw "GOT IT!";
            // return;
          }
          if (node.children && node.children.length > 0) {
            for (var i = 0; i < node.children.length; i  ) {
              getNodePath(node.children[i]);
            }

            //当前节点的子节点遍历完依旧没找到,则删除路径中的该节点
            temppath.pop();
          } else {
            //找到叶子节点时,删除路径当中的该叶子节点
            temppath.pop();
          }
        }

        for (let i = 0; i < arr.length; i  ) {
          getNodePath(arr[i]);
        }
      } catch (e) {
        return realPath;
      }
    },
    calcBottom(e) {
      console.log(e, this.currentExpend);

      return;
      this.$nextTick(() => {
        let obj = this.$refs.table.$el;
        var top = obj.getBoundingClientRect().top; //元素顶知端到可见区域道顶端的距离专
        var bottom = obj.getBoundingClientRect().bottom; //元素顶知端到可见区域道顶端的距离专
        var se = document.documentElement.clientHeight; //浏览器可见区域高度。属
        if (top <= se - 50 && bottom >= se) {
          this.positionType = false; //fix
        } else {
          this.positionType = true;
        }
      });
    },
    calcList(scrollTop = this.scrollTop) {
      console.time("js 运行时间:");

      this.startIndex = Math.floor(scrollTop / 65);
      this.virtualRows = this.form.rows.slice(
        this.startIndex,
        this.startIndex   10
      );
      let height = this.num * 65;
      let mainTable = this.$refs.table.$el.getElementsByClassName(
        "el-table__body"
      );

      Array.from(mainTable).forEach(v => {
        v.style.height = height   "px";
        if (this.startIndex   10 >= this.num) {
          v.style.paddingTop = scrollTop - 65   "px";
          v.style.paddingBottom = 0;
        } else {
          v.style.paddingTop = scrollTop   "px";
          v.style.paddingBottom = height - 10 * 65 - scrollTop   "px";
        }
      });
      this.$nextTick(() => {
        console.timeEnd("js 运行时间:");
      });
    }
  },
  mounted() {
    console.time("render300条时间:");
    this.form.rows = new Array(300).fill(0).map((v, i) => ({
      name: i
    }));
    this.form.rows = [
      ...[
        {
          id: "1",
          date: "2016-05-02",
          name: "王小虎1",
          address: "上海市普陀区金沙江路 1518 弄",
          customIndex: "1",
          children: [
            {
              name: "233",
              customIndex: "1.1",
              children: [{ name: "9", customIndex: "1.1.1" }]
            },
            {
              name: "7771",
              customIndex: "1.2",
              children: [
                { name: "9", customIndex: "1.2.1" },
                {
                  name: "9",
                  customIndex: "1.2.2"
                }
              ]
            }
          ]
        },
        {
          id: "2",
          date: "2016-05-04",
          name: "王小虎2",
          address: "上海市普陀区金沙江路 1517 弄",
          customIndex: "2",
          children: []
        }
      ],
      ...this.form.rows
    ];
    // this.calcList(this.form.rows);
    this.setIndex(this.form.rows);
    this.$nextTick(() => {
      this.debounceFn = _.debounce(() => {
        this.scrollTop = this.$refs.table.bodyWrapper.scrollTop;
      }, 100);
      this.$refs.table.bodyWrapper.addEventListener("scroll", this.debounceFn);
    });
    this.$nextTick(() => {
      console.timeEnd("render300条时间:");
    });
  },
  watch: {
    scrollTop(top) {
      // return;
      this.calcList(top);
    }
    // "form.rows": {
    //   handler(v) {
    //     this.setIndex(v);
    //     this.$nextTick(() => {
    //       // this.calcBottom()
    //     });
    //   },
    //   deep: true
    // }
  }
};
</script>

<style scoped>
#app {
  font-family: Helvetica, sans-serif;
  text-align: center;
}

.rea-type {
  height: 50px;
  line-height: 50px;
  text-align: center;
  width: 100%;
  margin-top: -20px;
  border: 1px solid red;
}

.fix-type {
  height: 50px;
  line-height: 50px;
  text-align: center;
  width: 100%;
  border: 1px solid red;
  position: fixed;
  bottom: 0;
}
.outLogin {
  width: 36px;
  height: 36px;
  float: right;
  margin-top: 15px;
  margin-left: 10px;
}
</style>

<style>
.vtable .el-table__body tbody {
}
</style>

树形列表

0 人点赞