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

别人的实现思路

推进方式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 .每次新增数据都需要滚动到显示最新数据

©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容

  • Swift1> Swift和OC的区别1.1> Swift没有地址/指针的概念1.2> 泛型1.3> 类型严谨 对...
    cosWriter阅读 11,172评论 1 32
  • 不知不觉中,我也已经二十一了(我自己觉得我是十五,而且不想接受反驳,哈哈),爱情这个话题对我来说,已经成为了...
    换一个昵称阅读 887评论 2 6
  • “学习、行动、分享”行动派的理念 从今年7月开始接触行动派到现在也有4个月了,却到现在才来看这本书。 一切都是最好...
    _巧克力_阅读 293评论 0 0
  • 今天早上5:30起床洗漱,和死党瑶瑶7:00到六楼吃早餐,7:25发出发到翰明阳,到了翰明阳才知道志燕没有提前...
    文铸颍阅读 258评论 0 1
  • 今天是孩子军训第二天。孩子回来身体都很累,但心情很好,同时精神也很好!身体累,是正常的啊,暑假期间一直没锻炼啊!心...
    源本精彩_养女日记阅读 323评论 0 0