虚拟列表非固定高度实现思路

别人的实现思路

推进方式1:初始化的时候

1 .一些数据的初始加功

_listData() {
      return this.listData.map((item, index) => {
        return {
          _index: `_${index}`,
          item
        };
      });
//把所有的数据都加上一个index序号

 visibleCount() {
      return Math.ceil(this.screenHeight / this.estimatedItemSize);
    },
//计算一张页面显示的数据

visibleData() {
      return this._listData.slice(this.start, this.end);
    }
//实际显示的数据
//这些都是在computed里面,会自动计算

initPositions() {
      this.positions = this.listData.map((d, index) => ({
        index,
        height: this.estimatedItemSize,
        top: index * this.estimatedItemSize,
        bottom: (index + 1) * this.estimatedItemSize
      }));
    },
//根据初始数据,算出默认的高度,以及默认的间隔

2 .根据数据渲染完数据的时候

this.$nextTick(function() {
      if (!this.$refs.items || !this.$refs.items.length) {
        return;
      }
      //获取真实元素大小,修改对应的尺寸缓存
      this.updateItemsSize();
      //更新列表总高度
      let height = this.positions[this.positions.length - 1].bottom;
      this.$refs.phantom.style.height = height + "px";
      //更新真实偏移量
      this.setStartOffset();
    });
//计算当前的显示元素的高度,更新里面默认的存储的高度.这个是他的实现的特色


//计算当前所有元素的高度并更新
updateItemsSize() {
      let nodes = this.$refs.items;
      nodes.forEach(node => {
        let rect = node.getBoundingClientRect();
        let height = rect.height;
        let index = +node.id.slice(1);
        let oldHeight = this.positions[index].height;
        let dValue = oldHeight - height;
        //存在差值:就是这个当前的高度和里面存的数据有差池,更新数据
        if (dValue) {
          this.positions[index].bottom = this.positions[index].bottom - dValue;
          this.positions[index].height = height;

          for (let k = index + 1; k < this.positions.length; k++) {
//这里需要更新这个数据后面的所有数据的高度
            this.positions[k].top = this.positions[k - 1].bottom;
            this.positions[k].bottom = this.positions[k].bottom - dValue;
          }
        }
      });
    },
//这里有两个感觉不太好的地方,其一就是每次都需要把当前的都算一遍,之前算过的也要在算一遍,如果算过的话,就不用再算了,其二就是当发现有变化,不仅这个数据的数据需要更新,后面的所有数据也需要一并更新,这样如果总的数据很大的话,不知道计算时间是多少,会不会造成页面的卡顿

推进方式2:滚动的时候

let scrollTop = this.$refs.list.scrollTop;
      //此时的开始索引
      this.start = this.getStartIndex(scrollTop);
      //此时的结束索引
      //这里有个二分法查询数据的算法
      this.end = this.start + this.visibleCount;
      //此时的偏移量
      //改变start,end。
      this.setStartOffset();

二分查找算法

binarySearch(list, value) {
      let start = 0;
      let end = list.length - 1;
      let tempIndex = null;
      while (start <= end) {
        let midIndex = parseInt((start + end) / 2);
        let midValue = list[midIndex].bottom;
        if (midValue === value) {
          return midIndex + 1;
        } else if (midValue < value) {
          start = midIndex + 1;
        } else if (midValue > value) {
          if (tempIndex === null || tempIndex > midIndex) {
            tempIndex = midIndex;
          }
          end = end - 1;
        }
      }
      return tempIndex;
    }

场景升级版本

1 .需要动态新增数据,并不是一开始就有所有数据
2 .每次新增数据都需要滚动到显示最新数据

你可能感兴趣的:(虚拟列表非固定高度实现思路)