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

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

重组件的优化

以下代码原理是使用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不卡顿,只渲染一万条

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

相关推荐
_丿丨丨_4 小时前
XSS(跨站脚本攻击)
前端·网络·xss
古月-一个C++方向的小白4 小时前
C++11之lambda表达式与包装器
开发语言·c++
天天进步20154 小时前
前端安全指南:防御XSS与CSRF攻击
前端·安全·xss
沐知全栈开发5 小时前
Eclipse 生成 jar 包
开发语言
呼啦啦呼啦啦啦啦啦啦5 小时前
利用pdfjs实现的pdf预览简单demo(包含翻页功能)
android·javascript·pdf
杭州杭州杭州6 小时前
Python笔记
开发语言·笔记·python
tanyongxi666 小时前
C++ AVL树实现详解:平衡二叉搜索树的原理与代码实现
开发语言·c++
拾光拾趣录7 小时前
括号生成算法
前端·算法
阿葱(聪)7 小时前
java 在k8s中的部署流程
java·开发语言·docker·kubernetes
拾光拾趣录8 小时前
requestIdleCallback:让你的网页如丝般顺滑
前端·性能优化