面试官:你项目中遇到过什么问题?都是怎么解决的啊?

515 阅读3分钟

好不容易通过了八股文的面试,终于要开始问项目了。

面试官:“你项目中遇到过什么问题?都是怎么解决的啊?” 你说:“我项目都比较简单,没遇到什么问题?可能那些问题对我而言没有什么条件😋” 面试官眉头紧锁🤷🏻‍♀️:“施主,出门右转~~~”

当你类似这样的回答(可能你会稍微委婉一点😂)基本上就已经宣告结束了。其实面试官在问这个问题的时候基本上都是想问的是你在项目中的亮点,有没有惊艳到他的地方。这时你就要证明给他看,你是一个能够发现问题,并且能够“漂亮”解决问题的人。

如果碰到面试官这样问,不妨我们就跟他扯一扯虚拟列表试试看。

什么是虚拟列表

那到底什么是虚拟列表呢?

我们在工作中可能会需要这种情况,不能使用分页来渲染列表数据,当数据量很小的时候基本上没有什么影响,但是如果把数据增加到一万条甚至十万条,那么此时会非常的耗时并且界面会很卡顿。这种情况很显然是接受不了的。(回答了面试官的第一个问题。)此时我们就可以用虚拟列表来解决这个问题。下面你就得需要做出解释了

虚拟列表是按需要显示列表的一种实现,也就是说只对可见区域的数据进行渲染,对不可见区域的数据不渲染或者部分渲染。

面试官:“听不懂!!!能说的详细一点吗?”这时你应该随机应变,拿过你的简历在空白的地方展现你的画图能力😋 你说:“比如我们想要看到的可见区域的数据只有7条,刚开始从0-6条数据就是我们初次看到的视图,假设我们设置的可视区域的高度为350px,忽略一些边界情况(padding margin 等)每个iterm的高度是50px。”

截屏2022-11-11 22.57.17.png 当我们滚动200px的时候,此时应该展现的是这个样子。 截屏2022-11-11 22.56.15.png

如何实现虚拟列表

实现虚拟列表就是在用户滚动的时候,改变可视区域的数据。具体操作如下:

  • 计算可视区域的起始数据的索引 startIndex
  • 计算可视区域的数据 visibleData
  • 计算可视区域在整个列表中的偏移量 offsetY

截屏2022-11-12 17.38.24.png 我们这边用vue3来实现。代码很简单我们直接看代码。

<template>
  <div class="virtual-list__container" @scroll="scrollEvent" :style="{height: `${containerHeight}px`}">
    <div class="virtual-list__blank" :style="{height: `${itemHeight * totalCount}px`}"></div>
    <div class="virtual-list__content" :style="{transform: `translate3d(0, ${offsetY}px, 0)`}">
      <div class="vitual-list__item" v-for="(item, index) in visibleData" :key="index" :style="{height: `${itemHeight}px`}">
        <div>{{item.value}}</div>
      </div>
    </div>
  </div>
</template>

<script setup lang="ts">
import {ref, computed} from 'vue';

const containerHeight = 350
const itemHeight = 50
const visibleCount = Math.ceil(containerHeight/itemHeight)

// 模拟数据
const totalCount = ref(100000) // 列表总数
const data = ref(Array.from({length:totalCount.value}).map((_, index) => ({value: index})))

const startIndex = ref(0)
const visibleData = computed(() => ( data.value.slice(startIndex.value, startIndex.value + visibleCount) ))

const offsetY = ref(0)

function scrollEvent(e) {
  const {scrollTop}= e.target
  startIndex.value = Math.floor(scrollTop/itemHeight)
  offsetY.value = scrollTop
}

</script>

<style lang="scss" scoped>
.virtual-list {
  &__container {
    width: 100%;
    overflow: auto;
    position: relative;
    border: 1px solid #f66
  }
  &__blank {
    position: absolute;
    top: 0;
    left: 0;
    right: 0;
  }
  &__content {
    transform: translate3d(0,0,0);
  }
}
</style>
  • virtual-list__container代表最外层我们设置高度的盒子为350px
  • virtual-list__blank为真实列表高度的盒子 为50 * totalCount (totalCount代表数据总数)
  • virtual-list__content可视区域部分

visibleData通过computed利用可视区域的起始索引startIndex和可视区域可显示的数据数量可以计算出。那我们现在需要做的就是通过滚动的高度来改变startIndex从而动态的计算visibleData渲染到视图即可。startIndex则通过滚动的高度除以每一个item的高度。这是面试官又来刁难你了

面试官:“如果可视区域的的最上面出现了只显示一般的数据,这个要怎么处理呢?”此时继续用画图来征服他。

截屏2022-11-12 19.04.04.png

面试官所描述的应该是这种场景。我们的代码Math.floor(scrollTop/itemHeight)就已经处理了这种情况。 最后我们把offsetY得值设置到:style="{transform: translate3d(0, ${offsetY}px, 0)}"将可视区域的部分平移即可。

点击查看代码

我们也可以封装成一个组件哦,大家可以思考一下。这篇文章主要是来介绍一个简单的虚拟列表,当然还有一些比较复杂的情况这里就不赘述了。大家觉得可以的话那就点个赞吧!😋