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

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

重组件的优化

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

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

相关推荐
知孤云出岫几秒前
web 渗透学习指南——初学者防入狱篇
前端·网络安全·渗透·web
贩卖纯净水.6 分钟前
Chrome调试工具(查看CSS属性)
前端·chrome
爱吃喵的鲤鱼8 分钟前
linux进程的状态之环境变量
linux·运维·服务器·开发语言·c++
DARLING Zero two♡35 分钟前
关于我、重生到500年前凭借C语言改变世界科技vlog.16——万字详解指针概念及技巧
c语言·开发语言·科技
Gu Gu Study37 分钟前
【用Java学习数据结构系列】泛型上界与通配符上界
java·开发语言
栈老师不回家1 小时前
Vue 计算属性和监听器
前端·javascript·vue.js
芊寻(嵌入式)1 小时前
C转C++学习笔记--基础知识摘录总结
开发语言·c++·笔记·学习
前端啊龙1 小时前
用vue3封装丶高仿element-plus里面的日期联级选择器,日期选择器
前端·javascript·vue.js
一颗松鼠1 小时前
JavaScript 闭包是什么?简单到看完就理解!
开发语言·前端·javascript·ecmascript
有梦想的咸鱼_1 小时前
go实现并发安全hashtable 拉链法
开发语言·golang·哈希算法