Vue.js решение для оптимизации производительности списка с бесконечной прокруткой

Vue.js

вопрос

Как мы все знаем, изменение DOM веб-страницы — дорогостоящая операция, которая выполняется намного медленнее, чем другие операции. Почему это? Потому что каждый раз, когда DOM модифицируется, браузеру часто приходится пересчитывать макет элемента и перерисовывать его. Также известен как оплавление и перерисовка. Особенно, если страница содержит большое количество элементов и сложную верстку, производительность пострадает. Какое практическое влияние это оказывает на пользователей?

Распространенным сценарием является рендеринг списка с большими объемами данных. Обычно это неупорядоченный список или таблица, которую можно прокручивать бесконечно, при большом количестве данных страница будет иметь явные зависания при прокрутке, что серьезно влияет на пользовательский опыт. Как это решить?

решение

Поскольку корень проблемы заключается в слишком большом количестве элементов DOM, найдите способ ограничить их количество.

  • Ограничивает количество элементов списка, видимых пользователю. Мы называем видимую область ViewPort
  • Когда список прокручивается, как другие элементы списка меняются с невидимых на видимые?
  • Слушайте событие прокрутки элемента контейнера списка, когда элемент в списке входит в видимую область, он добавляется в DOM
  • Проблема в том, что если вы продолжите прокручивать таким образом, список будет становиться все больше и больше. Поэтому его необходимо удалить из DOM, когда элемент списка покидает ViewPort.
  • Проблема возникает снова, так как ViewPort имеет размер всего одного экрана, когда элемент прокручивается, он не успевает отрисовываться, и какое-то время будет пустое пространство. Решение состоит в том, чтобы добавить часть рендеринга данных вверх и вниз.
    无限滚动

Это основная идея схемы оптимизации производительности бесконечной прокрутки.

В реальных проектах нам может не понадобиться реализовывать компонент бесконечного списка прокрутки с нуля, у Vue.js есть готовое колесо:vue-virtual-scroller.

Установите этот плагин в свой проект:

$ npm install -D vue-virtual-scroller

файл входа в проектmain.jsИмпортируйте этот плагин:

import "vue-virtual-scroller/dist/vue-virtual-scroller.css";
import Vue from "vue";
import VueVirtualScroller from "vue-virtual-scroller";

Vue.use(VueVirtualScroller);

Случай 1: виртуальный список

Давайте рассмотрим простой пример с использованиемvue-virtual-scrollerОтображение списка с большим количеством данных. Сначала сJSON-GeneratorСоздайте объект JSON из 5000 фрагментов данных и сохраните его вdata.jsonдокумент. Можно использовать следующие правила:

[
  '{{repeat(5000)}}',
  {
    _id: '{{objectId()}}',
    age: '{{integer(20, 40)}}',
    name: '{{firstName()}} {{surname()}}',
    company: '{{company().toUpperCase()}}'
  }
]

создать новыйVirtualList.vueфайл, импортdata.json, и назначьте его компонентуitemsАтрибуты. Затем положите<virtual-scroller>Компоненты:

VirtualList.vue:

<template>
  <virtual-scroller :items="items" item-height="40" content-tag="ul">
    <template slot-scope="props">
      <li :key="props.itemKey">{{props.item.name}}</li>
    </template>
  </virtual-scroller>
</template>

<script>
import items from "./data.json";

export default {
  data: () => ({ items })
};
</script>

virtual-scrollerКомпоненты должны быть установленыitem-height. Кроме того, поскольку мы собираемся создать список, мы можем установитьcontent-tag="ul", что означает, что содержимое отображается как<ul>Этикетка.

vue-virtual-scrollerподдерживать использованиеscoped slots, что повышает гибкость рендеринга контента. используяslot-scope="props", мы можем получить доступvue-virtual-scrollerвыставленные данные.

propsесть одинitemKeyсвойство, мы должны привязать его к корневому элементу раздела содержимого по соображениям производительности.:key="props.itemKey". Тогда мы можем пройтиprops.itemПолучите необработанные данные в формате JSON.

Если вы хотите оформить список, вы можете датьvirtual-scroller настраивать classАтрибуты:

<template>
  <virtual-scroller class="virtual-list" ...></virtual-scroller>
</template>

<style>
.virtual-list ul {
  list-style: none;
}
</style>

или вы также можете использоватьscopedстиль, с/deep/Селектор:

<style scoped>
.virtual-list /deep/ ul {
  list-style: none;
}
</style>

Случай 2: виртуальная таблица

аналогичныйVirtualList, давайте посмотрим на другой компонент формыVirtualTable: VirtualTable.vue:

<template>
  <virtual-scroller :items="items" item-height="40" content-tag="table">
    <template slot-scope="props">
      <tr :key="props.itemKey">
        <td>{{props.item.age}}</td>
        <td>{{props.item.name}}</td>
        <td>{{props.item.company}}</td>
      </tr>
    </template>
  </virtual-scroller>
</template>

<script>
import items from "./data.json";

export default {
  data: () => ({ items })
};
</script>

Здесь есть небольшая проблема, нам нужно добавить<thead>Ярлыки для отображения имен столбцов:AgeName а такжеCompany

К счастью, виртуальный скроллер поддерживает слоты и может настраивать различные части контента:

<main>
  <slot name="before-container"></slot>
  <container>
    <slot name="before-content"></slot>
    <content>
      <!-- Your items here -->
    </content>
    <slot name="after-content"></slot>
  </container>
  <slot name="after-container"></slot>
</main>

Каждый из этих слотов может содержать пользовательский контент.container Будет container-tagЗамена значения атрибута, по умолчаниюdiv,contentодеялоcontent-tagзамена стоимости.

использовать здесьbefore-contentслот плюс одинtheadПросто сделай это:

<template>
  <virtual-scroller
    :items="items"
    item-height="40"
    container-tag="table"
    content-tag="tbody"
    >
      <thead slot="before-content">
        <tr>
          <td>Age</td>
          <td>Name</td>
          <td>Company</td>
        </tr>
      </thead>
      <template slot-scope="props">
        <tr :key="props.itemKey">
          <td>{{props.item.age}}</td>
          <td>{{props.item.name}}</td>
          <td>{{props.item.company}}</td>
        </tr>
      </template>
  </virtual-scroller>
</template>

Обратите внимание, что мы ставимcontent-tag="table"изменился наcontent-tag="tbody", потому что мы установилиcontainer-tag="table", который должен построитьtableОбщая структура этикетки.

Если вы хотите добавитьtfoot, вы должны знать, как это сделать.

Суммировать

Мы научились оптимизировать производительность списков с бесконечной прокруткой и использоватьvue-virtual-scrollerПлагин Vue созданVirtualListа также VirtualTableкомпоненты. Если вы используете их для отображения 5000 фрагментов данных, сгенерированных ранее, вы сможете более плавно отображать и прокручивать. Дополнительные сведения об использовании см.документация по vue-виртуальному скроллеру.

Исходный код, задействованный в статьекликните сюда. Для получения дополнительной технической галантереи, пожалуйста, обратите внимание на мою общедоступную учетную запись WeChat: 1024 Translation Station.

微信公众号:1024译站