create-performant-virtualized-lists-vue.png
单独渲染DOM上的项目会给用户带来明显的性能滞后,特别是当他们滚动浏览大型列表时。为了使滚动更有效,我们应该使用虚拟滚动列表,这样可以提高页面的加载速度,防止网络应用的卡顿。

虚拟滚动列表类似于标准的滚动列表,然而,在任何时候都只有用户当前视图中的数据被呈现出来。当用户向下滚动页面时,新的项目会随着旧的项目被删除而被呈现出来。

在这篇文章中,我们将探讨vue-virtual-scroll-list,一个用于在Vue.js中创建虚拟滚动列表的神奇库。让我们开始吧!

在vue-virtual-scroll-list中渲染内容
vue-virtual-scroll-list库有两种主要的方法来将网页内容渲染成一个列表,即 item 模式和 v-for 模式。

item模式是渲染静态内容的理想选择。一旦内容被追加到DOM上,item模式就会释放出正在使用的内存。如果你改变了数据,你需要调用 forceRender() 并重新开始这个过程。

要渲染动态内容,更好的选择是v-for模式。在v-for模式下,提供给列表的数据在内存中被引用。因此,当数据发生变化时,列表项会被重新渲染,并且上下文被保持。

让我们仔细看看vue-virtual-scroll-list库,比较一下使用和不使用虚拟滚动列表的项目模式的性能。

首先,我们将建立一个新的Vue.js项目并安装vue-virtual-scroll-list。然后,我们将使用随机生成的数据创建一个列表。最后,我们将在有和没有虚拟滚动的情况下渲染我们的列表,比较各自的性能。

设置一个Vue.js项目

首先,确保你的机器上安装了Vue.js。用以下命令创建一个新的Vue.js项目。

  1. vue create virtual-scroll-demo

一旦项目设置完毕,安装vue-virtual-scroll-list库

  1. npm install vue-virtual-scroll-list --save

现在,我们的项目有如下结构:
new-vue-project-structure.png

生成一个列表

现在我们有了项目的基础,让我们开始为创建我们的两个列表打基础。

导航到你的/src文件夹,创建一个名为data.js的文件。让我们把下面这个生成随机数据的简单函数添加到 data.js 中:

  1. let idCounter = 0;
  2. export function getData(count) {
  3. const data = [];
  4. for (let index = 0; index < count; index++) {
  5. data.push({
  6. id: String(idCounter++),
  7. text: Math.random()
  8. .toString(16)
  9. .substr(10),
  10. });
  11. }
  12. return data;
  13. }

接下来,我们将创建一个名为Item.vue的新文件,它是我们要渲染的项目组件。在Item.vue中,我们将包括以下代码块,它为我们的列表创建一个模板和样式,以及检索和显示上面生成的数据的道具

  1. <template>
  2. <div class="item">
  3. <div class="id">{{ source.id }} - {{ source.text }}</div>
  4. </div>
  5. </template>
  6. <script>
  7. export default {
  8. name: 'item',
  9. props: {
  10. source: {
  11. type: Object,
  12. default() {
  13. return {}
  14. }
  15. }
  16. }
  17. }
  18. </script>
  19. <style scoped>
  20. .item {
  21. display: flex;
  22. flex-direction: column;
  23. border-bottom: 1px solid lightgrey;
  24. padding: 1em;
  25. }
  26. </style>

渲染一个没有虚拟滚动的列表

现在我们已经创建了一个列表,让我们在不使用vue-virtual-scroll-list的情况下在我们的DOM上渲染列表项。在App.vue中添加以下代码:

  1. <template>
  2. <div id="app">
  3. <div class="wrapper">
  4. <div class="list">
  5. <p v-for="item in items" :key="item">
  6. {{item}}
  7. </p>
  8. </div>
  9. </div>
  10. </div>
  11. </template>
  12. <script>
  13. import Item from './Item'
  14. import { getData } from './data'
  15. export default {
  16. name: 'App',
  17. data() {
  18. return {
  19. item: Item,
  20. items: getData(100000)
  21. }
  22. }
  23. }
  24. </script>
  25. <style>
  26. #app {
  27. text-align: center;
  28. color: #2c3e50;
  29. margin-top: 1em;
  30. padding: 1em;
  31. }
  32. .list {
  33. border: 2px solid red;
  34. border-radius: 3px;
  35. }
  36. </style>

在上面的代码块中,我们在DOM中渲染了100,000个item。让我们看看在这么多数据和没有虚拟滚动的情况下,我们的列表将如何表现。用下面的npm命令启动该项目:

  1. npm run serve

我们将得到如下结果
list-item-render-standard-scroll.png

当我们在浏览器中检查检查元素时,我们会看到所有的HTML元素都被追加到浏览器的DOM中,如下图所示
browser-inspect-element-html-output.png
在浏览器DOM中追加元素会增加DOM的大小。因此,浏览器将需要更多的时间来追加每一个项目到DOM中,可能会造成明显的性能滞后。让我们仔细观察一下浏览器将我们的列表追加到DOM中所花费的时间。
standard-list-component-browser-dom-load-time.png

事件DOMContentLoaded在22秒后触发,意味着浏览器标签在显示最终渲染的列表之前需要22秒的加载时间。同样,从下面的图片中可以看出,渲染我们的列表消耗了128MB的内存
standard-list-component-browser-dom-memory-consumption.png

用虚拟卷轴渲染一个列表

现在,让我们试着用虚拟滚动来渲染我们的列表。在main.js中导入vue-virtual-scroll-list包

  1. import Vue from "vue";
  2. import App from "./App.vue";
  3. Vue.config.productionTip = false;
  4. import VirtualList from "vue-virtual-scroll-list";
  5. Vue.component("virtual-list", VirtualList);
  6. new Vue({
  7. render: (h) => h(App),
  8. }).$mount("#app");

接下来,我们将为虚拟列表组件内的item渲染数据。让我们改变我们的App.js文件,使其看起来像下面的代码块

  1. <template>
  2. <div id="app">
  3. <div class="wrapper">
  4. <virtual-list
  5. class="list"
  6. style="height: 360px; overflow-y: auto;"
  7. :data-key="'id'"
  8. :data-sources="items"
  9. :data-component="item"
  10. :estimate-size="50"
  11. />
  12. </div>
  13. </div>
  14. </template>
  15. <script>
  16. import Item from './Item'
  17. import { getData } from './data'
  18. export default {
  19. name: 'App',
  20. data() {
  21. return {
  22. item: Item,
  23. items: getData(100000)
  24. }
  25. }
  26. }
  27. </script>
  28. <style>
  29. #app {
  30. text-align: center;
  31. color: #2c3e50;
  32. margin-top: 1em;
  33. padding: 1em;
  34. }
  35. .list {
  36. border: 2px solid red;
  37. border-radius: 3px;
  38. }
  39. </style>

注意,数据道具是虚拟列表渲染item所需要的。运行上面的代码块将给我们带来以下输出
virtual-scroll-component-output.png

我们可以在下面的图片中看到,一次只渲染了几个item。当用户向下滚动时,更多的item被呈现出来。
virtual-scroll-item-render-order.png

现在,我们的DOM树比以前小多了 当我们渲染我们的虚拟滚动列表时,DOMContentLoaded会比以前快得多!
virtual-scroll-list-dom-render-time.png

如上图所示,该事件仅在563毫秒内触发。同样地,我们的操作只消耗了79MB的内存,这比我们没有使用虚拟卷轴时要少得多
virtual-scroll-list-dom-memory-consumption.png

总结

现在你知道如何使用vue-virtual-scroll-list库在Vue.js中创建一个虚拟滚动的列表了吧!

在本教程中,我们创建了一个使用随机生成的数据的静态列表,然后在我们的Vue.js应用程序中实现了它,比较了它使用和不使用虚拟滚动的性能。

虚拟滚动列表的性能很高,特别是当你的网页上有大量的项目列表时。使用虚拟滚动列表可以提高页面的加载速度,并全面改善用户体验