在使用vue-virtual-list的 DynamicScroller时,子列表项之间出现了意想不到的间距

前端开发 2026-07-10

实际效果截图:

enter image description here

异常的空白区域用红色圈出。模板和CSS代码如下:

      <DynamicScroller
        :items="msg_list"
        :min-item-size="50"
        id="chat-box-container">
        <template v-slot="{ item, index, active }">
          <DynamicScrollerItem
            :item="item"
            :active="active"
            :size-dependencies="[item.message]"
            :data-index="index"
            :key="item.id">
            <div class="chat-box">
              <img class="avatar" :src="item.avatar" />
              <div class="chat-content-container">
                <div class="name">{{ item.username }}</div>
                <div class="chat-content">{{ item.content }}</div>
              </div>
            </div>
          </DynamicScrollerItem>
        </template>
      </DynamicScroller>
.chat-box {
  display: flex;
}
.avatar {
  width: 40px;
  height: 40px;
  border-radius: 50%;
  background-color: aqua;
}

.chat-content-container {
  margin-left: 10px;
}
.name {
  color: #d1d5db;
}
.chat-content {
  display: inline-block;
  margin-top: 10px;
  border: 2px solid rgba(185, 172, 172, 0.527);
  border-radius: 6px;
  background-color: rgba(185, 172, 172, 0.527);
  padding: 5px 10px;
  direction: ltr;

  color: #d1d5db;
}
#chat-box-container {
  border: 1px solid #fff;
  border-radius: 10px;
  padding: 10px;
  margin: 20px 20px;

  background-color: #36393f;
  overflow: auto;
}

数据源格式:

{
    "id": 1,
    "userID": 2,
    "avatar": "https://ts3.tc.mm.bing.net/th/id/OIP-C.7GLMYPqMlt2LgkbPsOnDIAAAAA?cb=ucfimg2ucfimg=1&rs=1&pid=ImgDetMain&o=7&rm=3",
    "content": "hello,我是管理员",
    "username": "admin",
    "createTime": "2026-04-05T13:14:18.000+00:00",
    "isDelete": 0
}

由于我在CSS中没有设置任何填充或外边距,我预计布局会遵循正常的文档流,如下图所示(不使用DynamicScroller的效果):

enter image description here

当我检查页面结构时,我发现把transformY属性添加到了每个子项,正是这个属性导致了间隙(因为我手动把transformY改为0 时,间隙就消失):

enter image description here

在这种情况下,所有项的高度都是56px。
我不知道为什么会有这样的transformY,而且上面图片所示的页面上只有四个元素,但所有数据都已渲染。这显然不正确。

我想知道我哪里出了问题,以及导致这些意外间隙和错误渲染行为的原因。
如果你能帮我,我将不胜感激 :)

解决方案

从你的代码片段来看,问题出在这里,你缺少对 vue-virtual-scroller 的必需CSS导入。我新建了一个Vue项目来测试,当我省略 import 'vue-virtual-scroller/dist/vue-virtual-scroller.css' 这一行时,结果如下:

Screenshot showing broken layout with gaps between items

请注意项之间的间隙,这与您在意外的 transformY 间距中所经历的情况相符。

然而,当我添加缺失的CSS导入后,虚拟滚动器就能够正确呈现:

Screenshot showing correct layout without gaps

完整可运行的代码如下:

<script setup lang="ts">
import { ref } from "vue";
import { DynamicScroller, DynamicScrollerItem } from "vue-virtual-scroller";
import "vue-virtual-scroller/dist/vue-virtual-scroller.css";

// Fake list data generation
const generateFakeList = (count = 500) => {
  const usernames = ["Alice", "Bob", "Charlie", "Diana", "Eve", "Frank", "Grace"];
  const avatars = [
    "https://i.pravatar.cc/150?img=1",
    "https://i.pravatar.cc/150?img=2",
    "https://i.pravatar.cc/150?img=3",
    "https://i.pravatar.cc/150?img=4",
    "https://i.pravatar.cc/150?img=5",
    "https://i.pravatar.cc/150?img=6",
    "https://i.pravatar.cc/150?img=7",
  ];
  const contents = [
    "Hey there!",
    "How are you?",
    "This is a longer message to test different heights in the virtual scroller component.",
    "👍",
    "See you later!",
    "Lorem ipsum dolor sit amet.",
    "Short",
  ];

  return Array.from({ length: count }, (_, i) => ({
    id: i + 1,
    username: usernames[i % usernames.length],
    avatar: avatars[i % avatars.length],
    content: contents[i % contents.length],
    message: contents[i % contents.length], // For size-dependencies
  }));
};

const msg_list = ref(generateFakeList(500));
</script>

<template>
  <DynamicScroller :items="msg_list" :min-item-size="50" id="chat-box-container">
    <template v-slot="{ item, index, active }">
      <DynamicScrollerItem
        :item="item"
        :active="active"
        :size-dependencies="[item.message]"
        :data-index="index"
        :key="item.id"
      >
        <div class="chat-box">
          <img class="avatar" :src="item.avatar" />
          <div class="chat-content-container">
            <div class="name">{{ item.username }}</div>
            <div class="chat-content">{{ item.content }}</div>
          </div>
        </div>
      </DynamicScrollerItem>
    </template>
  </DynamicScroller>
</template>

<style scoped>
.chat-box {
  display: flex;
}
.avatar {
  width: 40px;
  height: 40px;
  border-radius: 50%;
  background-color: aqua;
}

.chat-content-container {
  margin-left: 10px;
}
.name {
  color: #d1d5db;
}
.chat-content {
  display: inline-block;
  margin-top: 10px;
  border: 2px solid rgba(185, 172, 172, 0.527);
  border-radius: 6px;
  background-color: rgba(185, 172, 172, 0.527);
  padding: 5px 10px;
  direction: ltr;

  color: #d1d5db;
}
#chat-box-container {
  border: 1px solid #fff;
  border-radius: 10px;
  padding: 10px;
  margin: 20px 20px;

  background-color: #36393f;
  overflow: auto;
}
</style>

添加那一行就能完全解决问题。希望这能帮到你!

站内所有文章版权归属LeftHeroAI导航站,无授权禁止任何主体转载、抄袭、复制内容,亦不得私自架设镜像站点。一经侵权,本站将通过法律途径追责。

相关文章