Vue.js 无限滚动列表性能优化方案

问题

你们都知道,Web 页面修改 DOM 是开销较大的操做,相比其余操做要慢不少。这是为何呢?由于每次 DOM 修改,浏览器每每须要从新计算元素布局,再从新渲染。也就是所谓的重排(reflow)和重绘(repaint)。尤为是在页面包含大量元素和复杂布局的状况下,性能会受到影响。那对用户有什么实际的影响呢?css

一个常见的场景是大数据量的列表渲染。一般表现为可无限滚动的无序列表或者表格,当数据不少时,页面会出现明显的滚动卡顿,严重影响了用户体验。怎么解决呢?vue

解决方案

既然问题的根源是 DOM 元素太多,那就想办法限制元素数量。git

  • 限制列表对用户可见的元素数量。咱们把可见区域称为 ViewPort
  • 当列表滚动时,列表种的其余元素怎么由不可见变为可见?
  • 监听列表容器元素的滚动事件,当列表里的元素进入可视区域,则添加到DOM中
  • 问题是若是一直这么滚下去,列表会愈来愈大。因此须要在列表元素离开 ViewPort 的时候从DOM中移除
  • 问题又来了,因为 ViewPort 恰好是一屏的大小,滚动的时候元素还没来得及渲染,会出现一段时间的空白。解决办法就是上下增长一部分数据渲染。
    无限滚动

无限滚动的性能优化方案基本思路就是这样。github

在实际项目中,咱们可能不须要本身从头实现一个无限滚动列表组件,Vue.js 就有一个现成的轮子:vue-virtual-scrollernpm

在项目中安装这个插件:json

$ 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);
复制代码

案例一:VirtualList

咱们来看一个简单的例子,用vue-virtual-scroller渲染一个包含大量数据的列表。 先用 JSON-Generator 生成 5000 条数据的 JSON 对象,并保存到 data.json 文件。能够用下面的规则:性能优化

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

复制代码

新建一个 VirtualList.vue 文件,引入data.json,并将它赋值给组件的items属性。而后套一个 <virtual-scroller>组件:bash

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>

复制代码

案例二: VirtualTable

相似 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

幸亏 virtual-scroller 支持 slot,能够定制各部份内容:

<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>

复制代码

这些 slot 均可以放置自定义内容。container 会被 container-tag 属性值替换,默认是divcontent 被 content-tag 值替换。

这里用 before-content slot 加一个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-virtual-scroller 文档 。

文章涉及的源码 戳这里。更多技术干货,欢迎关注个人微信公众号:1024译站。

微信公众号:1024译站
相关文章
相关标签/搜索