0


前端渲染优化常用总结-滚动分页加载、虚拟列表、延迟加载IntersectionObserver

背景

有时候数据量大,页面请求数量过多会造成不好的体验,比如接口响应时间慢、并发请求多,渲染慢等等。最近就遇到了类似的优化需求,主要是三种滚动分页加载、虚拟列表、延迟加载,在这里记录一下他们的使用场景、以及个人实现的总结。欢迎大佬指正~

一、滚动分页加载

场景:

滚动分页加载主要是为了在首次渲染时更快的加载数据,在一些没有分页器但是数据量较多的页面使用。需要后端接口支持分页。

思路:

初始的时候请求多少数据?1、可以默认设置一个pageSize(页面大小)2、也可以根据视口的高度来计算一个初始的pageSize,需要监听窗口的大小改变。

什么时候加载下一页数据?监听滚动事件,当滚动条到达底部时,(可见高度(clientHeight)+已滚动的距离(scrollTop) >= 元素滚动区域的高度(scrollHeight))需要加载下一页的数据,并将数据拼接到至已有数据中。

刷新数据怎么操作?如需要刷新列表,则要将已有数据清空,并将当前的页码置为1。

实现:

 listenScrollFn() {
    const domRef = this.$refs.domRef as HTMLElement;
    domRef.addEventListener('scroll', async (e: any) => {
      const event = e.target;
      // 判断是否滚动到底部
      if (event.clientHeight + event.scrollTop + 5 >= event.scrollHeight && !this.loading) 
      {
          // 判断当前是否已经是最后一页
        if (this.pagination.currentPage * this.pagination.pageSize < this.totalCount) {
          // 加载下一页数据
          this.pagination.currentPage++;
          await this.loadData();
        } else return;
      }
    });
  }

二、延迟加载

场景:

延迟加载主要是避免当前页面首次渲染时并发请求接口数量过多,可以优化为先请求可视区域部分,再延迟加载剩余部分,这样可以大大减少接口并发请求同时优化首屏渲染速度。

思路:

关于IntersectionObserver?IntersectionObserver 对象,用于推断某些节点是否可以被用户看见、有多大比例可以被用户看见。

主要使用到的属性和方法:

observe() 开始观察

unobserve()停止观察

disconnect()关闭观察

intersectionRatio 目标元素可见比例

什么时候开始加载数据?根据intersectionRatio来判断当前元素是否已经出现在视口中或者出现的比例为多少,来决定是否加载相关数据。

刷新数据怎么操作?调用observe() 重新开始观察即可

实现:

也可以封装为自定义指令,但是对于如果要刷新数据的场景,可能不太方便。

 lazyLoadObserver: any = {};
    listenViewPort(fn: any) {
        this.lazyLoadObserver = new IntersectionObserver((entries, observer) => {
            entries.forEach((entry, index) => {
                let lazyDom = entry.target;
                // intersectionRatio 目标元素可见比例
                if (entry.intersectionRatio > 0) {
                    fn();
                    observer.unobserve(lazyDom);
                }
            });
        });
        this.lazyLoadObserver.observe(this.$refs.domRef as Element);
    }
    beforeDestroy() {
        this.lazyLoadObserver.disconnect()
    }

三、虚拟列表

场景:

虚拟列表主要是为了优化长列表的渲染速度,只渲染可视区域部分,如当请求到的数据量很大时,一次性渲染可能会导致卡顿,体验不佳。与第一种的区别是虚拟渲染页面固定渲染元素的个数,不会随着滚动使得页面元素变多,同时不需要后端接口支持分页。

思路:

元素结构?

可视区域能渲染多少个元素?

visibleCount= 通过容器的高度/列表每一项的高度即可

如何截取当前要渲染的数据?

startIndex=** 当前滚动的距离scrollTop/**列表每一项的高度itemHeight

从startIndex开始截取visibleCount条数据渲染即可

滚动后要做哪些操作?

1、计算出要渲染的数据

2、将列表容器 list-wrap-content 向下移动,保证所有数据在视口中

实现:

 <div class="list-wrap" ref="listWrapRef" @scroll="getVisibleData">
    <div
      class="list-wrap-scroll"
      :style="{ height: `${listData.length * this.itemHeight}px` }"
    ></div>
    <div class="list-wrap-content" ref="listWrapContentRef">
      <div class="list-wrap-content-item" v-for="item in visibleData" :key="item">{{ item }}</div>
    </div>
  </div>
  data() {
    return {
      listData: new Array(200).fill(1).map((item, index) => `item-${index + 1}`),
      itemHeight: 50,
      listHeight: 600,
      visibleData: [],
    };
  },
  computed: {
 
    visibleCount() {
      return ~~(this.listHeight / this.itemHeight);
    },
  },
  methods: {
    getVisibleData() {
      const scrollTop = this.$refs.listWrapRef.scrollTop;
      const startIndex = ~~(scrollTop / this.itemHeight);
      const endIndex = startIndex + this.visibleCount;
      // 截取数据
      this.visibleData = this.listData.slice(startIndex, endIndex);
      // 移动内容
      this.$refs.listWrapContentRef.style.transform = `translate3d(0,${
        startIndex * this.itemHeight
      }px,0)`;
    },
  },
  created() {},
  mounted() {
    this.getVisibleData();
  },
.list-wrap {
  height: 600px;
  width: 360px;
  border: 1px solid;
  overflow: auto;
  position: relative;
  &-scroll {
    position: absolute;
    left: 0;
    top: 0;
    right: 0;
    z-index: -1;
  }
  &-content {
    &-item {
      height: 50px;
      color: blue;
      line-height: 50px;
      text-align: center;
      border: 1px solid lightblue;
      box-sizing: border-box;
    }
  }
}
标签: 前端

本文转载自: https://blog.csdn.net/weixin_44667515/article/details/139593871
版权归原作者 陈Chen. 所有, 如有侵权,请联系我们删除。

“前端渲染优化常用总结-滚动分页加载、虚拟列表、延迟加载IntersectionObserver”的评论:

还没有评论