虚拟滚动

QVirtualScroll 可以每次只渲染长列表中用户视图中可见的那一小部分,并在用户滚动容器中更新可见的项目。每次只有可见区域的数据被渲染,最小化渲染 DOM 树的性能和内存开销。

目前有两种类型的 QVirtualScroll:“list” (使用 QItems) 和 “table” (使用表格样式显示数据行).

QVirtualScroll API

QVirtualScroll API


virtual-scroll-horizontal
: Boolean
说明
在水平模式下使虚拟列表工作
scroll-target
: Element | String
说明
用作自定义滚动容器的 CSS 选择器或 DOM 元素,而不是自动检测到的容器。

用法

TIP

  • (Composition API) 为了在使用大型列表时获得最好的性能,请不要使用 ref()/computed()/reactive() 等函数包裹传给 items 属性的数组,这样可以让 Vue 跳过对此列表的响应式跟踪。
  • (Options API) 为了在使用大型列表时获得最好的性能,请使用 Object.freeze(items) 冻结传给 items 属性的数组,这样可以让 Vue 跳过对此列表的响应式跟踪。
  • 将被渲染的数据数量会基于 virtual-scroll-item-size 属性和可滚动区域的大小来计算,但是您可以通过 virtual-scroll-slice-size 属性来实现您的需求。
  • 使用 virtual-scroll-item-size 属性来指定元素的大小(宽或高的像素大小)。当一个元素被渲染在屏幕上后,它的大小是自动更新的,但如果您指定的元素大小接近实际大小,您将获得更好的初始滚动位置。无论您是否使用这个属性,QVirtualScroll 都可以正常工作,但是如果不使用它,您可能会遇到连续滚动时滚动条不跟随鼠标指示位置(在桌面设备上)的问题,或者容器实际滚动的位置与预计的位置稍微偏移一到两个元素的问题(在移动设备上)。

WARNING

每个浏览器都会给滚动容器限制一个最大高度。在 IE11 中,这大约为 1,000,000px,而在其余浏览器中,它的内容更大,但仍然有限。

滚动下面的示例,查看 QVirtualScroll 的运行情况。

基础



<template>
  <q-virtual-scroll
    style="max-height: 300px;"
    :items="heavyList"
    separator
    v-slot="{ item, index }"
  >
    <q-item
      :key="index"
      dense
    >
      <q-item-section>
        <q-item-label>
          #{{ index }} - {{ item.label }}
        </q-item-label>
      </q-item-section>
    </q-item>
  </q-virtual-scroll>
</template>

#0 - Option 1
#1 - Option 2
#2 - Option 3
#3 - Option 4
#4 - Option 5
#5 - Option 6
#6 - Option 7
#7 - Option 8
#8 - Option 9
#9 - Option 10
#10 - Option 11
#11 - Option 12
#12 - Option 13
#13 - Option 14
#14 - Option 15
#15 - Option 16
#16 - Option 17
#17 - Option 18
#18 - Option 19
#19 - Option 20
#20 - Option 21
#21 - Option 22
#22 - Option 23
#23 - Option 24
#24 - Option 25
#25 - Option 26
#26 - Option 27
#27 - Option 28
#28 - Option 29
#29 - Option 30
#30 - Option 31
#31 - Option 32
#32 - Option 33
#33 - Option 34
#34 - Option 35
#35 - Option 36
#36 - Option 37
#37 - Option 38
#38 - Option 39

水平的



<template>
  <q-virtual-scroll
    :items="heavyList"
    virtual-scroll-horizontal
    v-slot="{ item, index }"
  >
    <div
      :key="index"
      :class="item.class"
    >
      #{{ index }} - {{ item.label }}
    </div>
  </q-virtual-scroll>
</template>

#0 - Option 1
#1 - Option 2
#2 - Option 3
#3 - Option 4
#4 - Option 5
#5 - Option 6
#6 - Option 7
#7 - Option 8
#8 - Option 9
#9 - Option 10
#10 - Option 11
#11 - Option 12
#12 - Option 13
#13 - Option 14
#14 - Option 15
#15 - Option 16
#16 - Option 17
#17 - Option 18
#18 - Option 19
#19 - Option 20
#20 - Option 21
#21 - Option 22
#22 - Option 23
#23 - Option 24
#24 - Option 25
#25 - Option 26
#26 - Option 27
#27 - Option 28
#28 - Option 29
#29 - Option 30
#30 - Option 31
#31 - Option 32
#32 - Option 33
#33 - Option 34
#34 - Option 35
#35 - Option 36
#36 - Option 37
#37 - Option 38
#38 - Option 39
#39 - Option 40
#40 - Option 41
#41 - Option 42
#42 - Option 43
#43 - Option 44
#44 - Option 45
#45 - Option 46
#46 - Option 47
#47 - Option 48
#48 - Option 49
#49 - Option 50
#50 - Option 51
#51 - Option 52
#52 - Option 53
#53 - Option 54
#54 - Option 55
#55 - Option 56
#56 - Option 57
#57 - Option 58
#58 - Option 59
#59 - Option 60
#60 - Option 61
#61 - Option 62
#62 - Option 63
#63 - Option 64
#64 - Option 65
#65 - Option 66
#66 - Option 67
#67 - Option 68
#68 - Option 69
#69 - Option 70
#70 - Option 71
#71 - Option 72
#72 - Option 73
#73 - Option 74
#74 - Option 75
#75 - Option 76
#76 - Option 77
#77 - Option 78
#78 - Option 79
#79 - Option 80
#80 - Option 81
#81 - Option 82
#82 - Option 83
#83 - Option 84
#84 - Option 85
#85 - Option 86
#86 - Option 87
#87 - Option 88
#88 - Option 89
#89 - Option 90
#90 - Option 91
#91 - Option 92
#92 - Option 93
#93 - Option 94
#94 - Option 95
#95 - Option 96
#96 - Option 97
#97 - Option 98
#98 - Option 99
#99 - Option 100
#100 - Option 101
#101 - Option 102

不同的模版



<template>
  <q-virtual-scroll
    style="max-height: 300px;"
    :items="heavyList"
    separator
    v-slot="{ item, index }"
  >
    <q-banner v-if="item.banner === true" class="bg-black text-white q-py-xl" :key="'a' + index">
      #{{ index }} - {{ item.label }}
    </q-banner>

    <q-item
      v-else
      :key="'b' + index"
      dense
      clickable
    >
      <q-item-section>
        <q-item-label>
          #{{ index }} - {{ item.label }}
        </q-item-label>
      </q-item-section>
    </q-item>
  </q-virtual-scroll>
</template>



<template>
  <q-virtual-scroll
    :items="heavyList"
    virtual-scroll-horizontal
    v-slot="{ item, index }"
  >
    <div :key="index" class="row items-center">
      <q-separator v-if="index === 0" vertical spaced />

      <q-avatar v-if="item.avatar === true" class="bg-black text-white q-my-md">
        {{ index % 10 + 1 }}
      </q-avatar>

      <q-item
        v-else
        dense
        clickable
      >
        <q-item-section>
          <q-item-label>
            #{{ index }} - {{ item.label }}
          </q-item-label>
        </q-item-section>
      </q-item>

      <q-separator vertical spaced />
    </div>
  </q-virtual-scroll>
</template>


1





6





1


表格类型

注意使用的 type="table" 属性。



<template>
  <div class="q-pa-md">
    <q-virtual-scroll
      type="table"
      style="max-height: 70vh"
      :virtual-scroll-item-size="48"
      :virtual-scroll-sticky-size-start="48"
      :virtual-scroll-sticky-size-end="32"
      :items="heavyList"
      v-slot="{ item: row, index }"
    >
      <tr :key="index">
        <td>#{{ index }}</td>
        <td v-for="col in columns" :key="index + '-' + col">
          {{ row[col] }}
        </td>
      </tr>
    </q-virtual-scroll>
  </div>
</template>

#0Frozen Yogurt15962448714%1%
#1Ice cream sandwich2379374.31298%1%
#2Eclair262162363376%7%
#3Cupcake3053.7674.34133%8%
#4Gingerbread35616493.93277%16%
#5Jelly bean3750940500%0%
#6Lollipop3920.2980380%2%
#7Honeycomb4083.2876.55620%45%
#8Donut45225514.93262%22%
#9KitKat518266575412%6%
#10Frozen Yogurt15962448714%1%
#11Ice cream sandwich2379374.31298%1%
#12Eclair262162363376%7%
#13Cupcake3053.7674.34133%8%
#14Gingerbread35616493.93277%16%
#15Jelly bean3750940500%0%
#16Lollipop3920.2980380%2%
#17Honeycomb4083.2876.55620%45%
#18Donut45225514.93262%22%
#19KitKat518266575412%6%
#20Frozen Yogurt15962448714%1%
#21Ice cream sandwich2379374.31298%1%
#22Eclair262162363376%7%
#23Cupcake3053.7674.34133%8%
#24Gingerbread35616493.93277%16%
#25Jelly bean3750940500%0%
#26Lollipop3920.2980380%2%

与内容一起滚动的表头



<template>
  <div class="q-pa-md">
    <q-virtual-scroll
      type="table"
      style="max-height: 70vh"
      :virtual-scroll-item-size="48"
      :virtual-scroll-sticky-size-start="48"
      :virtual-scroll-sticky-size-end="32"
      :items="heavyList"
    >
      <template v-slot:before>
        <thead class="text-left">
          <tr>
            <th>Index</th>
            <th v-for="col in columns" :key="'1--' + col.name">
              {{ col.name }}
            </th>
          </tr>
        </thead>
      </template>

      <template v-slot:after>
        <tfoot class="text-left">
          <tr>
            <th>Index</th>
            <th v-for="col in columns" :key="'2--' + col.name">
              {{ col.name }}
            </th>
          </tr>
        </tfoot>
      </template>

      <template v-slot="{ item: row, index }">
        <tr :key="index">
          <td>#{{ index }}</td>
          <td v-for="column in columns" :key="index + '-' + column.name">
            {{ row[column.prop] }}
          </td>
        </tr>
      </template>
    </q-virtual-scroll>
  </div>
</template>

IndexDessert (100g serving)CaloriesFat (g)Carbs (g)Protein (g)Sodium (mg)Calcium (%)
#0Frozen Yogurt15962448714%
#1Ice cream sandwich2379374.31298%
#2Eclair262162363376%
#3Cupcake3053.7674.34133%
#4Gingerbread35616493.93277%
#5Jelly bean3750940500%
#6Lollipop3920.2980380%
#7Honeycomb4083.2876.55620%
#8Donut45225514.93262%
#9KitKat518266575412%
#10Frozen Yogurt15962448714%
#11Ice cream sandwich2379374.31298%
#12Eclair262162363376%
#13Cupcake3053.7674.34133%
#14Gingerbread35616493.93277%
#15Jelly bean3750940500%
#16Lollipop3920.2980380%
#17Honeycomb4083.2876.55620%
#18Donut45225514.93262%
#19KitKat518266575412%
#20Frozen Yogurt15962448714%
#21Ice cream sandwich2379374.31298%
#22Eclair262162363376%
#23Cupcake3053.7674.34133%
#24Gingerbread35616493.93277%
#25Jelly bean3750940500%
#26Lollipop3920.2980380%
IndexDessert (100g serving)CaloriesFat (g)Carbs (g)Protein (g)Sodium (mg)Calcium (%)

请注意下面的示例中表头和表尾都使用了 “position: sticky” 相关的 CSS 来使其固定。还需要注意使用了头部和尾部的插槽。



<template>
  <div class="q-pa-md">
    <q-virtual-scroll
      type="table"
      style="max-height: 70vh"
      :virtual-scroll-item-size="48"
      :virtual-scroll-sticky-size-start="48"
      :virtual-scroll-sticky-size-end="32"
      :items="heavyList"
    >
      <template v-slot:before>
        <thead class="thead-sticky text-left">
          <tr>
            <th>Index</th>
            <th v-for="col in columns" :key="'1--' + col.name">
              {{ col.name }}
            </th>
          </tr>
        </thead>
      </template>

      <template v-slot:after>
        <tfoot class="tfoot-sticky text-left">
          <tr>
            <th>Index</th>
            <th v-for="col in columns" :key="'2--' + col.name">
              {{ col.name }}
            </th>
          </tr>
        </tfoot>
      </template>

      <template v-slot="{ item: row, index }">
        <tr :key="index">
          <td>#{{ index }}</td>
          <td v-for="col in columns" :key="index + '-' + col.name">
            {{ row[col.prop] }}
          </td>
        </tr>
      </template>
    </q-virtual-scroll>
  </div>
</template>

IndexDessert (100g serving)CaloriesFat (g)Carbs (g)Protein (g)Sodium (mg)Calcium (%)
#0Frozen Yogurt15962448714%
#1Ice cream sandwich2379374.31298%
#2Eclair262162363376%
#3Cupcake3053.7674.34133%
#4Gingerbread35616493.93277%
#5Jelly bean3750940500%
#6Lollipop3920.2980380%
#7Honeycomb4083.2876.55620%
#8Donut45225514.93262%
#9KitKat518266575412%
#10Frozen Yogurt15962448714%
#11Ice cream sandwich2379374.31298%
#12Eclair262162363376%
#13Cupcake3053.7674.34133%
#14Gingerbread35616493.93277%
#15Jelly bean3750940500%
#16Lollipop3920.2980380%
#17Honeycomb4083.2876.55620%
#18Donut45225514.93262%
#19KitKat518266575412%
#20Frozen Yogurt15962448714%
#21Ice cream sandwich2379374.31298%
#22Eclair262162363376%
#23Cupcake3053.7674.34133%
#24Gingerbread35616493.93277%
#25Jelly bean3750940500%
#26Lollipop3920.2980380%
IndexDessert (100g serving)CaloriesFat (g)Carbs (g)Protein (g)Sodium (mg)Calcium (%)

下面是一个更复杂的例子。



<template>
  <div class="q-pa-md">
    <q-virtual-scroll
      type="table"
      style="max-height: 70vh"
      :virtual-scroll-item-size="48"
      :virtual-scroll-sticky-size-start="48"
      :virtual-scroll-sticky-size-end="32"
      :items="heavyList"
    >
      <template v-slot:before>
        <thead class="thead-custom-sticky text-left">
          <tr>
            <th>#</th>
            <th v-for="col in columns" :key="'1--' + col.name2">
              {{ col.name1 }}
            </th>
          </tr>
          <tr>
            <th>Index</th>
            <th v-for="col in columns" :key="'2--' + col.name2">
              {{ col.name2 }}
            </th>
          </tr>
        </thead>
      </template>

      <template v-slot:after>
        <tfoot class="tfoot-custom-sticky text-left">
          <tr>
            <th>#</th>
            <th v-for="col in columns" :key="'3--' + col.name2">
              {{ col.name1 }}
            </th>
          </tr>
          <tr>
            <th>Index</th>
            <th v-for="col in columns" :key="'4--' + col.name2">
              {{ col.name2 }}
            </th>
          </tr>
        </tfoot>
      </template>

      <template v-slot="{ item: row, index }">
        <tr :key="index">
          <td>#{{ index }}</td>
          <td v-for="col in columns" :key="index + '-' + col.name2">
            {{ row[col.prop] }}
          </td>
        </tr>
      </template>
    </q-virtual-scroll>
  </div>
</template>

#(100g serving)(val)(g)(g)(g)(mg)(%)
IndexDessertCaloriesFatCarbsProteinSodiumCalcium
#0Frozen Yogurt15962448714%
#1Ice cream sandwich2379374.31298%
#2Eclair262162363376%
#3Cupcake3053.7674.34133%
#4Gingerbread35616493.93277%
#5Jelly bean3750940500%
#6Lollipop3920.2980380%
#7Honeycomb4083.2876.55620%
#8Donut45225514.93262%
#9KitKat518266575412%
#10Frozen Yogurt15962448714%
#11Ice cream sandwich2379374.31298%
#12Eclair262162363376%
#13Cupcake3053.7674.34133%
#14Gingerbread35616493.93277%
#15Jelly bean3750940500%
#16Lollipop3920.2980380%
#17Honeycomb4083.2876.55620%
#18Donut45225514.93262%
#19KitKat518266575412%
#20Frozen Yogurt15962448714%
#21Ice cream sandwich2379374.31298%
#22Eclair262162363376%
#23Cupcake3053.7674.34133%
#24Gingerbread35616493.93277%
#25Jelly bean3750940500%
#26Lollipop3920.2980380%
#(100g serving)(val)(g)(g)(g)(mg)(%)
IndexDessertCaloriesFatCarbsProteinSodiumCalcium

滚动目标

如果您想指定滚动的目标(自动检测的目标不是您想要的),您可以使用 scroll-target 属性并传递一个 CSS 选择器或者一个 DOM 元素。

如果您需要使用整个页面作为虚拟列表的滚动元素,请将滚动目标设置为 scroll-target="body"

WARNING

  • 如果您通过 scroll-target 属性自定义了滚动目标容器,那么必须确保该元素存在且可以溢出(他必须具有最大高度允许滚动溢出)
  • 如果滚动目标容器无法溢出,则会出现整个列表都被渲染的情况。

WARNING

如果您想为 scroll-target 使用一个 Vue 引用,那么请在组件完成挂载在后设置,如下所示:



<template>
  <div id="virtual-scroll-target" class="scroll" style="max-height: 230px">
    <div class="q-pa-md bg-yellow">
      Above the list - scrolls with the list
    </div>

    <q-virtual-scroll
      scroll-target="#virtual-scroll-target"
      :items="heavyList"
      separator
      v-slot="{ item, index }"
    >
      <q-item
        :key="index"
        dense
      >
        <q-item-section>
          <q-item-label>
            #{{ index }} - {{ item.label }}
          </q-item-label>
        </q-item-section>
      </q-item>
    </q-virtual-scroll>

    <div class="q-pa-md bg-yellow">
      Below the list - scrolls with the list
    </div>
  </div>
</template>

Above the list - scrolls with the list
#0 - Option 1
#1 - Option 2
#2 - Option 3
#3 - Option 4
#4 - Option 5
#5 - Option 6
#6 - Option 7
#7 - Option 8
#8 - Option 9
#9 - Option 10
#10 - Option 11
#11 - Option 12
#12 - Option 13
#13 - Option 14
#14 - Option 15
#15 - Option 16
#16 - Option 17
#17 - Option 18
#18 - Option 19
#19 - Option 20
#20 - Option 21
#21 - Option 22
#22 - Option 23
#23 - Option 24
#24 - Option 25
#25 - Option 26
#26 - Option 27
#27 - Option 28
#28 - Option 29
#29 - Option 30
Below the list - scrolls with the list


<template>
  <div ref="virtualListScrollTargetRef" class="scroll" style="max-height: 230px">
    <div class="q-pa-md bg-yellow">
      Above the list - scrolls with the list
    </div>

    <q-virtual-scroll
      :scroll-target="scrollTarget"
      :items="heavyList"
      separator
      v-slot="{ item, index }"
    >
      <q-item
        :key="index"
        dense
      >
        <q-item-section>
          <q-item-label>
            #{{ index }} - {{ item.label }}
          </q-item-label>
        </q-item-section>
      </q-item>
    </q-virtual-scroll>

    <div class="q-pa-md bg-yellow">
      Below the list - scrolls with the list
    </div>
  </div>
</template>

Above the list - scrolls with the list
#0 - Option 1
#1 - Option 2
#2 - Option 3
#3 - Option 4
#4 - Option 5
#5 - Option 6
#6 - Option 7
#7 - Option 8
#8 - Option 9
#9 - Option 10
#10 - Option 11
#11 - Option 12
#12 - Option 13
#13 - Option 14
#14 - Option 15
#15 - Option 16
#16 - Option 17
#17 - Option 18
#18 - Option 19
#19 - Option 20
#20 - Option 21
#21 - Option 22
#22 - Option 23
#23 - Option 24
#24 - Option 25
#25 - Option 26
#26 - Option 27
#27 - Option 28
#28 - Option 29
#29 - Option 30
Below the list - scrolls with the list


<template>
  <div class="q-ma-md">
    <q-scroll-area
      :thumb-style="thumbStyle"
      :bar-style="barStyle"
      style="height: 200px"
      id="scroll-area-with-virtual-scroll-1"
    >
      <q-virtual-scroll
        scroll-target="#scroll-area-with-virtual-scroll-1 > .scroll"
        :items="heavyList"
        :virtual-scroll-item-size="32"
        separator
        v-slot="{ item, index }"
      >
        <q-item
          :key="index"
          dense
        >
          <q-item-section>
            <q-item-label>
              #{{ index }} - {{ item.label }}
            </q-item-label>
          </q-item-section>
        </q-item>
      </q-virtual-scroll>
    </q-scroll-area>
  </div>
</template>

#0 - Option 1
#1 - Option 2
#2 - Option 3
#3 - Option 4
#4 - Option 5
#5 - Option 6
#6 - Option 7
#7 - Option 8
#8 - Option 9
#9 - Option 10
#10 - Option 11
#11 - Option 12
#12 - Option 13
#13 - Option 14
#14 - Option 15
#15 - Option 16
#16 - Option 17
#17 - Option 18
#18 - Option 19
#19 - Option 20
#20 - Option 21

滚动到指定位置



<template>
  <div>
    <div class="q-pa-md row justify-center">
      <q-input
        style="min-width: 10em"
        type="number"
        v-model.number="virtualListIndex"
        :min="0"
        :max="9999"
        label="Scroll to index"
        input-class="text-right"
        outlined
      />
      <q-btn
        class="q-ml-sm"
        label="Go"
        no-caps
        color="primary"
        @click="executeScroll"
      />
    </div>

    <q-separator />

    <q-virtual-scroll
      ref="virtualListRef"
      style="max-height: 300px;"
      component="q-list"
      :items="heavyList"
      separator
      @virtual-scroll="onVirtualScroll"
      v-slot="{ item, index }"
    >
      <q-item
        :key="index"
        dense
        :class="{ 'bg-black text-white': index === virtualListIndex }"
      >
        <q-item-section>
          <q-item-label>
            #{{ index }} - {{ item.label }}
          </q-item-label>
        </q-item-section>
      </q-item>
    </q-virtual-scroll>
  </div>
</template>


#0 - Option 1
#1 - Option 2
#2 - Option 3
#3 - Option 4
#4 - Option 5
#5 - Option 6
#6 - Option 7
#7 - Option 8
#8 - Option 9
#9 - Option 10
#10 - Option 11
#11 - Option 12
#12 - Option 13
#13 - Option 14
#14 - Option 15
#15 - Option 16
#16 - Option 17
#17 - Option 18
#18 - Option 19
#19 - Option 20
#20 - Option 21
#21 - Option 22
#22 - Option 23
#23 - Option 24
#24 - Option 25
#25 - Option 26
#26 - Option 27
#27 - Option 28
#28 - Option 29
#29 - Option 30
#30 - Option 31
#31 - Option 32
#32 - Option 33
#33 - Option 34
#34 - Option 35
#35 - Option 36
#36 - Option 37
#37 - Option 38
#38 - Option 39

同步和异步

您还可以使用 items-fn 属性生成要在列表上显示的项目。

WARNING

确保使用一个同步函数来返回要显示的项目列表。

如果您需要异步数据,请使用一个检索和渲染数据的组件。



<template>
  <q-virtual-scroll
    style="max-height: 300px; overflow-x: hidden"
    :items-size="size"
    :items-fn="getItems"
    :virtual-scroll-item-size="78"
    separator
    v-slot="{ item, index }"
  >
    <async-component :key="index" :index="item.index" :sent="item.sent"></async-component>
  </q-virtual-scroll>
</template>

工具 CSS 类

这里有两个工具 CSS 类名可以控制虚滚动的大小计算:

  • 使用 q-virtual-scroll--with-prev 类可以使被虚拟滚动渲染的元素与上一个元素一起分组(主要用于从同一行数据生成的多个表行)。
  • 使用 q-virtual-scroll--skip 类可以使被虚拟滚动渲染的元素在计算大小时忽略此元素的大小。


<template>
  <div class="q-pa-md">
    <q-table
      style="height: 400px"
      ref="tableRef"
      title="Treats"
      :rows="rows"
      :columns="columns"
      :table-colspan="9"
      row-key="index"
      virtual-scroll
      :virtual-scroll-item-size="48"
      :pagination="pagination"
      :rows-per-page-options="[0]"
    >

      <template v-slot:header="props">
        <q-tr :props="props">
          <q-th />

          <q-th
            v-for="col in props.cols"
            :key="col.name"
            :props="props"
          >
            {{ col.label }}
          </q-th>
        </q-tr>
      </template>

      <template v-slot:body="props">
        <q-tr :props="props" :key="`m_${props.row.index}`">
          <q-td>
            Index: {{ props.row.index }}
          </q-td>

          <q-td
            v-for="col in props.cols"
            :key="col.name"
            :props="props"
          >
            {{ col.value }}
          </q-td>
        </q-tr>
        <q-tr :props="props" :key="`e_${props.row.index}`" class="q-virtual-scroll--with-prev">
          <q-td colspan="100%">
            <div class="text-left">This is the second row generated from the same data: {{ props.row.name }} (Index: {{ props.row.index }}).</div>
          </q-td>
        </q-tr>
      </template>

    </q-table>
  </div>
</template>