The problem

As you all know, modifying the DOM on a Web page is an expensive operation and is much slower than other operations. Why is that? Because each time the DOM is modified, the browser often needs to recalculate the element layout and re-render it. Also known as reflow and repaint. Especially when pages contain a large number of elements and complex layouts, performance suffers. What are the practical implications for users?

A common scenario is large data volume list rendering. It is usually shown as an unordered list or table that can scroll indefinitely. When there is a lot of data, the page will appear obvious scrolling lag, which seriously affects the user experience. How do you solve it?

The solution

Since the root of the problem is too many DOM elements, try to limit the number of elements.

  • Limits the number of elements visible to the user. We call the visible area a ViewPort
  • When a list scrolls, how do other elements of the list go from invisible to visible?
  • Listen for the scrolling event of a list container element, which is added to the DOM when the list element is visible
  • The problem is if you keep rolling, the list keeps getting bigger and bigger. So the list element needs to be removed from the DOM when it leaves the ViewPort
  • The problem is that since the ViewPort is exactly the size of a screen, scrolling will leave the element blank for a while before rendering. The solution is to add a bit of data rendering up and down.

This is the basic idea of a performance optimization scheme for infinite scrolling.

In a real project, we might not need to implement an infinite scrolling list component from scratch ourselves, vue.js has a ready-made wheel: vue-Virtual-scroller.

Install this plug-in in your project:

$ npm install -D vue-virtual-scroller
Copy the code

The project entry file main.js introduces this plugin:

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

Vue.use(VueVirtualScroller);
Copy the code

Case 1: VirtualList

Let’s take a look at a simple example of using vue-Virtual-Scroller to render a list containing a large amount of data. Use JSON-generator to generate a JSON object with 5000 pieces of data and save it to a data. JSON file. The following rules can be used:

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

Create a new VirtualList. Vue file, import data.json, and assign it to the items property of the component. Then set a < virtual-Scroller > component:

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>

Copy the code

Virtual-scroller components must set item-height. Also, since we’re creating a list, we can set content-Tag =”ul” to render the content as a

    tag.

Vue-virtual-scroller supports scoped slots for increased flexibility in content rendering. We can access vue-virtual-Scroller exposed data by using slot-scope=”props”.

Props has an itemKey attribute, and for performance reasons we should bind the root element of the content section :key=”props. ItemKey “. Then we can use props. Item to get the raw data in JSON.

If you want to style the list, you can set the virtual-Scroller class property:

<template>
  <virtual-scroller class="virtual-list". ></virtual-scroller> </template> <style> .virtual-list ul { list-style: none; } </style>Copy the code

Alternatively, we can use scoped with the /deep/ selector:

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

Copy the code

Case 2: VirtualTable

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>

Copy the code

There is a small problem here. We need to add a tag to display the column names: Age, Name, and Company

Thanks to Virtual-Scroller’s slot support, you can customize the following parts:

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

Copy the code

Each of these slots can hold custom content. Container is replaced by the value of the container-tag attribute. The default value is div. Content is replaced by the value of the Content-tag attribute.

To do this, add thead to before-content slot:

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

Copy the code

Notice that we changed content-tag=”table” to content-tag=”tbody” because we set the container-tag=”table” to construct the normal structure of the table tag.

If you want to add a tfoot, you should know how to do it.

conclusion

We learned about performance optimization for an infinite scroll list and created VirtualList and VirtualTable components using the Vue-Virtual-Scroller Vue plug-in. If you use them to display the 5000 previously generated data, you should be able to render and scroll more smoothly. For more usage, refer to the vue-virtual-scroller documentation.

The source code involved in the article is here. More technical dry goods, welcome to follow my wechat public number: 1024 translation station.