简体   繁体   English

VueJS,Vuetify,数据表 - 可扩展,性能问题

[英]VueJS, Vuetify, data-table - expandable, performance problem

I've got a problem with my VueJS and Vuetify project.我的 VueJS 和 Vuetify 项目有问题。 I wanna create a table with expandable rows.我想创建一个带有可扩展行的表。 It'll be a table of orders with possibility to see bought products for each one.这将是一张订单表,可以查看每个订单的购买产品。 For one page it should show at least 100 rows of orders.对于一页,它应该显示至少 100 行订单。 For this, I used <v-data-table> from the Vuetify framework.为此,我使用了 Vuetify 框架<v-data-table>


What is the problem?问题是什么?

After preparing everything I realized that it works, but for expansion for each row, I have to wait a few seconds (it's too long - it must be a fast system).在准备好一切之后,我意识到它可以工作,但是对于每一行的扩展,我必须等待几秒钟(它太长了 - 它必须是一个快速的系统)。 And for expanding all visible records it is necessary to wait more than 20 seconds with whole page lag.并且为了扩展所有可见记录,需要等待超过20 秒的整页延迟。


What I've tried?我试过什么?

I started with standard Vuetify <v-data-table> with a show-expand prop and with an expanded-item slot - it was my first try - the slowliest.我从标准的 Vuetify <v-data-table>开始,带有一个show-expand道具和一个 expand expanded-item插槽 - 这是我的第一次尝试 - 最慢。 Secondly, I tried to create on my own - but with Vuetify:其次,我尝试自己创建 - 但使用 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>

What's interesting - I realized that v-if works faster than v-show , which is a weird fact, because I thought that changing display: none to nothing should be less problematic than adding/removing whole objects to DOM.有趣的是 - 我意识到v-ifv-show工作得更快,这是一个奇怪的事实,因为我认为将display: none更改为 none 应该比将整个对象添加/删除到 DOM 问题更小。

This method was a little faster than first, but it is still too slow.这种方法比第一种方法快一点,但还是太慢了。

I found a hint to set :ripple="false" for every v-btn in my tables and I did it - helped, but only a bit.我找到了一个提示,为我的表中的每个v-btn设置:ripple="false"并且我做到了 - 有所帮助,但只有一点点。 Everything was tested on Chrome and Firefox, on three devices with Windows and Linux Fedora and two android smartphones.一切都在 Chrome 和 Firefox、Windows 和 Linux Fedora 和两部 ZC31B32364CE19CA8ZFCD1 智能手机的三台设备上进行了测试。


What should else I do?我还应该怎么做?

Thank you in advance!先感谢您!

This excellent article suggests that the raw number of DOM nodes has the biggest impact on performance . 这篇优秀的文章表明 DOM 节点的原始数量对性能的影响最大 That said, I didn't experience any real performance bottlenecks in the sample app that I built to learn more about your problem.也就是说,在我构建的示例应用程序中,我没有遇到任何真正的性能瓶颈,以了解有关您的问题的更多信息。 The entire page with the table loaded in about 1.25s (from localhost), regardless of whether it was in dev mode or it was a production build.包含表格的整个页面在大约 1.25 秒内加载(来自本地主机),无论它是处于开发模式还是生产版本。 The JavaScriptconsole timer reported that expanding or contracting ALL 100 rows simultaneously only took an average of about 0.3s. JavaScript控制台计时器报告说,同时扩展或收缩所有 100 行平均只需要大约 0.3 秒。 Bottom line, I think you can achieve the optimizations you're looking for and not have to give up the conveniences of Vuetify.最重要的是,我认为您可以实现您正在寻找的优化,而不必放弃 Vuetify 的便利。

Recommendations建议

  1. Consider displaying fewer rows at one time (biggest expected impact)考虑一次显示更少的行(最大的预期影响)
  2. Streamline your template to use as few elements as possible, only display data that's really necessary to users.简化您的模板以使用尽可能少的元素,仅显示用户真正需要的数据。 Do you really need a v-data-table inside a v-data-table ?您真的需要v-data-tablev-data-table吗?
  3. Streamline your data model and only retrieve the bare minimum data you need to display the table.简化您的数据 model 并仅检索显示表格所需的最少数据。 As @Codeply-er suggested, the size and complexity of your data could be causing this strain正如@Codeply-er 建议的那样,数据的大小和复杂性可能会导致这种压力

Testing Method测试方法

Here's what I did.这就是我所做的。 I created a simple Vue/Vuetify app with a VDataTable with 100 expandable rows.我创建了一个简单的 Vue/Vuetify 应用程序,其中包含一个具有 100 个可扩展行的VDataTable (The data was pulled from the random user API ). (数据来自随机用户 API )。 I used this method to count DOM nodes.我使用这种方法来计算 DOM 节点。 Here are some of the parameters/info:以下是一些参数/信息:

  • Rows: 100行数:100
  • Columns: 5 + the expansion toggler列:5 + 扩展切换器
  • Expansion row content: a VSimpleTable with the user's picture and address扩展行内容:一个带有用户图片和地址的VSimpleTable
  • Size of a single JSON record returned from the API: ~62 lines (about half the size of your sample object above)从 API 返回的单个 JSON 记录的大小:~62 行(大约是上述示例 object 大小的一半)
  • Vue v2.6.11 Vue v2.6.11
  • Vuetify v2.3.0-beta.0 Vuetify v2.3.0-beta.0
    (I realize this just came out, but I don't think you'd have different results using v2.2.x) (我意识到这刚刚出来,但我认为使用 v2.2.x 不会有不同的结果)
  • App was built with vue create myapp and vue add vuetify应用程序是使用vue create myappvue add vuetify
  • VDataTable actually adds/removes the expansion rows from the DOM whenever the rows are expanded/contracted每当扩展/收缩行时, VDataTable实际上会从 DOM 中添加/删除扩展行

Here's some approximate stats on the result (these numbers fluctuated slightly in different conditions--YMMV):以下是结果的一些近似统计数据(这些数字在不同条件下略有波动——YMMV):

  • 773 (~7/row): number of DOM nodes in 100 rows/5 columns without expansion enabled 773 (~7/row): 100 行/5 列的 DOM 节点数,启用扩展
  • 977 (+2/row): number of nodes with expansion enabled 977(+2/行):启用扩展节点数
  • 24: number of nodes added to the table by expanding a single row 24:通过展开单行添加到表中的节点数
  • 3378 (+26/row): total nodes with ALL rows expanded 3378(+26/行):扩展所有行的节点总数
  • ~1.25s to load the entire page on a hard refresh大约 1.25 秒在硬刷新时加载整个页面
  • ~0.3s to expand or contract ALL of the nodes simultaneously ~0.3s 同时扩展或收缩所有节点
  • Sorting the columns with the built-in sorting tools was fast and very usable使用内置排序工具对列进行排序非常快速且非常有用

Here's code of the App.vue page of my app.这是我的应用的App.vue页面的代码。 The v-data-table almost the only component on the page (except the toggle button) and I didn't import any external components. 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>

You can see a working demo in this codeply .你可以在这个 codeply 中看到一个工作演示 Hope this helps!希望这可以帮助!

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM