重组件的优化和页面渲染十万条数据

重组件的优化和页面渲染十万条数据的优化

重组件的优化

以下代码原理是使用requestAnimationFrame(callback) 方法

vue2写法

Test01.vue

javascript 复制代码
<template>
  <div class="container">
    <div v-for="n in 100" :key="n">
      <HeavyCom v-if="defer(n)"></HeavyCom>
    </div>
  </div>
</template>

<script>
import HeavyCom from "@/views/HeavyCom";

export default {
  components: { HeavyCom },
  data() {
    return {
      frameCount: 0,
    };
  },
  created() {
    this.updateFrameCount();
  },
  methods: {
    updateFrameCount() {
      const maxCount = 100;
      this.frameCount++;
      if (this.frameCount < maxCount) {
        requestAnimationFrame(this.updateFrameCount);
      }
    },
    defer(n) {
      return this.frameCount >= n;
    },
  },
};
</script>

<style>
.container {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  grid-gap: 1em;
}
</style>

子组件HeavyCom.vue

javascript 复制代码
<template>
  <div class="item-container">
    <div class="item" v-for="n in 5000" :key="n"></div>
  </div>
</template>

<script>
export default {
  name: "HeavyCom"
}
</script>

<style lang="scss">
.item-container {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  border: 3px solid #f40;
  width: 600px;
  height: 600px;
  box-sizing: border-box;
  .item {
    width: 4px;
    height: 4px;
    background: #ccc;
    margin: 1px;
  }
}
</style>

vue3写法

Test01.vue

javascript 复制代码
<template>
  <div class="container">
    <div v-for="n in 100" :key="n">
      <HeavyComp v-if="defer(n)"></HeavyComp>
    </div>
  </div>
</template>
<script setup>
import HeavyComp from "@/views/HeavyComp";
import { useDefer } from './useDefer'
const defer = useDefer();
</script>

<style>
.container {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  grid-gap: 1em;
}
</style>

子组件HeavyComp.vue

javascript 复制代码
<template>
  <div class="item-container">
    <div class="item" v-for="n in 5000" :key="n"></div>
  </div>
</template>

<style>
.item-container {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  border: 3px solid #f40;
}
.item {
  width: 5px;
  height: 3px;
  background: #ccc;
  margin: 0.1em;
}
</style>

useDefer.js

javascript 复制代码
import {ref, onUnmounted} from "vue";
export function useDefer(maxCount = 100) {
    const frameCount = ref(0);
    let rafId;
    function updateFrameCount() {
        rafId = requestAnimationFrame(() => {
            frameCount.value++
            if (frameCount.value >= maxCount) {
                return;
            }
            updateFrameCount();
        });
    }
    updateFrameCount();
    onUnmounted(() => {
        cancelAnimationFrame(rafId);
    });
    return function defer(n) {
        console.log(frameCount.value, n);
        return frameCount.value >= n;
    }
}

结果:这里为了录制gif不卡顿,只渲染50个重组件

优点: 首屏渲染很快,后续的再依次加载

缺点: 快速滚动时,会出现短暂的白屏

页面渲染十万条数据的优化

使用虚拟列表的方式

通过这张图来表示虚拟列表,红框代表你的手机,黑条代表一条条数据

思路:我们只要知道手机屏幕 最多能放下几条数据 ,当下拉 滑动时,通过双指针 的方式截取相应的数据就可以了。

🚩 PS:为了防止滑动过快 导致的白屏 现象,我们可以使用预加载的方式多加载一些数据出来。

在Test02.vue

javascript 复制代码
<template>
  <div ref="list" class="v-scroll" @scroll="scrollEvent($event)">
    <div class="infinite-list" :style="{ height: listHeight + 'px' }"></div>

    <div class="scroll-list" :style="{ transform: getTransform }">
      <div ref="items" class="scroll-item" v-for="item in visibleData" :key="item.id" :style="{ height: itemHeight + 'px',lineHeight: itemHeight + 'px' }">{{ item.msg }}</div>
    </div>
  </div>
</template>

<script>
export default {
  name: "Test02",
  data() {
    return {
      // 数据
      listData: [],
      // 每项的高度
      itemHeight: 60,
      //可视区域高度
      screenHeight: 600,
      //偏移量
      startOffset: 0,
      //起始索引
      start: 0,
      //结束索引
      end: null,
    };
  },
  computed: {
    //列表总高度
    listHeight() {
      return this.listData.length * this.itemHeight;
    },
    //可显示的列表项数
    visibleCount() {
      return Math.ceil(this.screenHeight / this.itemHeight);
    },
    //偏移量对应的style
    getTransform() {
      return `translate(0,${this.startOffset}px)`;
    },
    //获取真实显示列表数据
    visibleData() {
      return this.listData.slice(this.start, Math.min(this.end, this.listData.length));
    }
  },
  methods: {
    scrollEvent() {
      //当前滚动位置
      let scrollTop = this.$refs.list.scrollTop;
      //此时的开始索引
      this.start = Math.floor(scrollTop / this.itemHeight);
      //此时的结束索引
      this.end = this.start + this.visibleCount;
      //此时的偏移量
      this.startOffset = scrollTop - (scrollTop % this.itemHeight);
    }
  },
  mounted() {
    for (let i = 1; i <= 100000; i++) {
      this.listData.push({id: i, msg: i})
    }
    this.start = 0;
    this.end = this.start + this.visibleCount;
  }
}
</script>

<style>
.v-scroll {
  height: 600px;
  width: 400px;
  border: 3px solid #000;
  overflow: auto;
  position: relative;
  -webkit-overflow-scrolling: touch;
}

.infinite-list {
  position: absolute;
  left: 0;
  top: 0;
  right: 0;
  z-index: -1;
}

.scroll-list {
  left: 0;
  right: 0;
  top: 0;
  position: absolute;
  text-align: center;
}

.scroll-item {
  padding: 10px;
  color: #555;
  box-sizing: border-box;
  border-bottom: 1px solid #999;
}
</style>

结果:这里为了录制gif不卡顿,只渲染一万条

优点:页面上只渲染出可视区域的内容,非常丝滑,无白屏现象

相关推荐
Yhame.6 分钟前
深入理解 Java 中的 ArrayList 和 List:泛型与动态数组
java·开发语言
鑫~阳1 小时前
html + css 淘宝网实战
前端·css·html
Catherinemin1 小时前
CSS|14 z-index
前端·css
mazo_command2 小时前
【MATLAB课设五子棋教程】(附源码)
开发语言·matlab
IT猿手2 小时前
多目标应用(一):多目标麋鹿优化算法(MOEHO)求解10个工程应用,提供完整MATLAB代码
开发语言·人工智能·算法·机器学习·matlab
青春男大2 小时前
java栈--数据结构
java·开发语言·数据结构·学习·eclipse
88号技师2 小时前
几款性能优秀的差分进化算法DE(SaDE、JADE,SHADE,LSHADE、LSHADE_SPACMA、LSHADE_EpSin)-附Matlab免费代码
开发语言·人工智能·算法·matlab·优化算法
Zer0_on2 小时前
数据结构栈和队列
c语言·开发语言·数据结构
一只小bit2 小时前
数据结构之栈,队列,树
c语言·开发语言·数据结构·c++
2401_882727573 小时前
低代码配置式组态软件-BY组态
前端·后端·物联网·低代码·前端框架