VueJS, Vuetify, таблица данных - расширяемая, проблема с производительностью - PullRequest
0 голосов
/ 27 апреля 2020

У меня проблема с моим VueJS и проектом Vuetify. Я хочу создать таблицу с расширяемыми строками. Это будет таблица заказов с возможностью просмотра купленных продуктов для каждого. На одной странице должно отображаться не менее 100 строк заказов. Для этого я использовал <v-data-table> из среды Vuetify.


В чем проблема?

После подготовки всего я понял, что это работает, но для расширения для каждой строки я придется подождать несколько секунд (это слишком долго - это должна быть быстрая система). А чтобы развернуть все видимые записи, нужно подождать более 20 секунд с целым отставанием страницы.


Что я пробовал?

Я начал с Стандартный Vuetify <v-data-table> с опорой show-expand и слотом expanded-item - это была моя первая попытка - самая медленная. Во-вторых, я пытался создать самостоятельно - но с помощью Vuetify:

<v-data-table>
 <template v-slot:item="{item}">
   <td @click="item.expanded = !item.expanded">expand / hide</td>
   <!--- [my table content here - too long to post it here] -->
   <tr v-if="item.expanded">
     <td :colspan="headers.length">
     <v-data-table>
       <!--- [content of the nested table - also too long to post it here] -->
     </v-data-table>
   </tr>
 </template>
</v-data-table>

Что интересно - я понял, что v-if работает быстрее, чем v-show, что странно, потому что я считал, что изменение display: none на ничто должно быть менее проблематичным c, чем добавление / удаление целых объектов в DOM.

Этот метод был немного быстрее первого, но все еще слишком медленный.

Я нашел подсказку для установки :ripple="false" для каждого v-btn в моих таблицах, и я сделал это - помогло, но только немного. Все было протестировано на Chrome и Firefox, на трех устройствах с Windows и Linux Fedora и двумя android смартфонами.


Что еще мне делать?

Заранее спасибо!

1 Ответ

1 голос
/ 28 апреля 2020

В этой превосходной статье предполагается, что необработанное количество узлов DOM оказывает наибольшее влияние на производительность . Тем не менее, я не испытывал каких-либо реальных узких мест в производительности в образце приложения, которое я создал, чтобы узнать больше о вашей проблеме. Вся страница с таблицей загружается примерно за 1,25 с (из localhost), независимо от того, была ли она в режиме разработки или это была производственная сборка. Консольный таймер JavaScript сообщил, что расширение или сжатие ВСЕХ 100 строк одновременно заняло в среднем около 0,3 с. В итоге, я думаю, что вы можете достичь оптимизации, которую вы ищете, и не должны отказываться от удобства Vuetify.

Рекомендации

  1. Рассмотрите возможность отображения меньшего количества строк одновременно ( наибольшее ожидаемое влияние)
  2. Оптимизируйте свой шаблон, чтобы использовать как можно меньше элементов, отображать только те данные, которые действительно необходимы пользователям. Вы действительно нуждаетесь в v-data-table внутри a v-data-table?
  3. Оптимизируйте свою модель данных и извлекайте только те минимальные данные, которые необходимы для отображения таблицы. Как предположил @ Codeply-er, размер и сложность ваших данных могут быть причиной такого напряжения

Метод тестирования

Вот что я сделал. Я создал простое приложение Vue / Vuetify с VDataTable с 100 расширяемыми строками. (Данные были получены из API случайного пользователя ). Я использовал этот метод для подсчета узлов DOM. Вот некоторые параметры / информация:

  • Строки: 100
  • Столбцы: 5 + переключатель расширения
  • Содержимое строки расширения: a VSimpleTable с изображение и адрес пользователя
  • Размер одной JSON записи, возвращаемой из API: ~ 62 строки (примерно вдвое меньше размера вашего образца объекта выше)
  • Vue v2.6.11
  • Vuetify v2.3.0-beta.0
    (я понимаю, что это только что вышло, но я не думаю, что вы получите другие результаты, используя v2.2.x)
  • Приложение было создано с vue create myapp и vue add vuetify
  • VDataTable фактически добавляет / удаляет строки расширения из DOM всякий раз, когда строки расширяются / сжимаются

Вот приблизительная статистика результата (эти числа слегка колебались в разных условиях - YMMV):

  • 773 (~ 7 / строка): количество узлов DOM в 100 строках / 5 столбцов без расширение включено
  • 977 (+ 2 / строка): количество узлов с расширение включено
  • 24: количество узлы, добавленные в таблицу путем расширения одной строки
  • 3378 (+ 26 / строки): общее количество узлов со ВСЕМИ развернутыми строками
  • ~ 1,25 с для загрузки всей страницы на жестком обновлении sh
  • ~ 0,3 с для расширения или сжатия ВСЕХ узлов одновременно
  • Сортировка столбцов с помощью встроенных инструментов сортировки была быстрой и очень удобной

Вот код App.vue страницы моего приложения. v-data-table почти единственный компонент на странице (кроме переключателя), и я не импортировал никаких внешних компонентов.

<template>
  <v-app>
    <v-btn
      color="primary"
      @click="toggleExpansion"
    >
      Toggle Expand All
    </v-btn>
    <v-data-table
      :expanded.sync="expanded"
      :headers="headers"
      :items="items"
      item-key="login.uuid"
      :items-per-page="100"
      show-expand
    >
      <template #item.name="{ value: name }">
        {{ name.first }} {{ name.last }}
      </template>
      <template #expanded-item="{ headers, item: person }">
        <td :colspan="headers.length">
          <v-card
            class="ma-2"
            max-width="500px"
          >
            <v-row>
              <v-col cols="4">
                <v-img
                  :aspect-ratio="1"
                  contain
                  :src="person.picture.thumbnail"
                />
              </v-col>
              <v-col cols="8">
                <v-simple-table>
                  <template #default>
                    <tbody>
                      <tr>
                        <th>Name</th>
                        <td class="text-capitalize">
                          {{ person.name.title }}. {{ person.name.first }} {{ person.name.last }}
                        </td>
                      </tr>
                      <tr>
                        <th>Address</th>
                        <td class="text-capitalize">
                          {{ person.location.street.number }} {{ person.location.street.name }}<br>
                          {{ person.location.city }}, {{ person.location.state }} {{ person.location.postcode }}
                        </td>
                      </tr>
                      <tr>
                        <th>DOB</th>
                        <td>
                          {{ (new Date(person.dob.date)).toLocaleDateString() }} (age {{ person.dob.age }})
                        </td>
                      </tr>
                    </tbody>
                  </template>
                </v-simple-table>
              </v-col>
            </v-row>
          </v-card>
        </td>
      </template>
    </v-data-table>
  </v-app>
</template>

<script>
  import axios from 'axios'
  export default {
    name: 'App',
    data: () => ({
      expanded: [],
      headers: [
        { text: 'Name', value: 'name' },
        { text: 'Gender', value: 'gender' },
        { text: 'Phone', value: 'phone' },
        { text: 'Cell', value: 'cell' },
        { text: 'Country', value: 'nat' },
        { text: '', value: 'data-table-expand' },
      ],
      items: [],
    }),
    created () {
      axios.get('https://randomuser.me/api/?seed=stackoverflow&results=100')
        .then(response => {
          this.items = response.data.results
        })
    },
    methods: {
      toggleExpansion () {
        console.time('expansion toggle')
        this.expanded = this.expanded.length ? [] : this.items
        console.timeEnd('expansion toggle')
      },
    },
  }
</script>

Вы можете увидеть рабочую демонстрацию в этом codeply . Надеюсь, это поможет!

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...