Recently review some optimization schemes for long lists. When it comes to long lists, vue-virtual-Scroller is the wheel most frequently involved in vUE stack.

In order to clarify more “why”, so a simple analysis of the plug-in source code.

See the source directory, there are mainly RecycleScroller. Vue, DynamicScroller. Vue and DynamicScrollerItem.vue these three components, but RecycleScroller for the core.

I saw two different implementations on demo. What’s the difference between them? In the application, the height of RecycleScroller item is static, that is, the height of each item in the list is consistent. DynamicScroller can be compatible with the height of item as dynamic. But theoretically RecycleScroller can also realize dynamic height item, as long as there is a scheme to calculate the height of item (DynamicScrollerItem is to solve this problem).

To analyze a JS library, we need to analyze the corresponding entry or package configuration file from package.json in the directory.

From the directory./build we can go to the corresponding packaging script, the entry is./ SRC /index.js. Open index.js and you can see that the plugin implements the requirements by registering global component plug-ins.

function registerComponents (Vue, prefix) {
  Vue.component(`${prefix}recycle-scroller`, RecycleScroller)
  Vue.component(`${prefix}RecycleScroller`, RecycleScroller)
  Vue.component(`${prefix}dynamic-scroller`, DynamicScroller)
  Vue.component(`${prefix}DynamicScroller`, DynamicScroller)
  Vue.component(`${prefix}dynamic-scroller-item`, DynamicScrollerItem)
  Vue.component(`${prefix}DynamicScrollerItem`, DynamicScrollerItem)
}
Copy the code

After a brief analysis of index.js, look at the Vue component files in the./ SRC /components/ directory.

Next, we will analyze the RecycleScroller. Vue file as the base.

<div
  v-observe-visibility="handleVisibilityChange"
  class="vue-recycle-scroller"
  :class="{ ready, 'page-mode': pageMode, [`direction-${direction}`]: true, }"
  @scroll.passive="handleScroll"
>
  <! -- $slots.before -->
  <! -- List loop item section -->
  <! -- $slots.after -->
</div>
Copy the code

Import {ObserveVisibility} from ‘vue-observe-visibility’ import {ObserveVisibility} from ‘vue-observe-visibility’ import {ObserveVisibility} from ‘vue-observe-visibility’

computed: {
  sizes () {
    if (this.itemSize === null) {
      // ...
      for (let i = 0, l = items.length; i < l; i++) {
        current = items[i][field] || minItemSize
        if (current < computedMinSize) {
          computedMinSize = current
        }
        accumulator += current
        sizes[i] = { accumulator, size: current }
      }
      // ...
      return sizes  // Return an array of size(height) for each item
    }
    return[]}},Copy the code

The main implementation principle is to use this.updatevisibleItems () to calculate startIndex, and endIndex to get the array of elements to render. Scroll: {start: XXX, end: XXX}. Calculate startIndex from viewport viewport range… EndIndex Specifies the style value of each element, which is controlled by CSS3’s Transform. The code is

style="ready ? { transform: `translate${direction === 'vertical' ? 'Y' : 'X'}(${view.position}px)` } : null"
Copy the code

You might think, well, if you have a long list of data, the demo generated 1W+, and you go through every scroll once, it’s going to be a very complicated algorithm. So this is where you need some algorithmic knowledge.

In the calculation process, dichotomy method is used to improve the execution efficiency of the program.

// Searching for startIndex
do {
  oldI = i
  h = sizes[i].accumulator
  if (h < scroll.start) {
    a = i
  } else if (i < count - 1 && sizes[i + 1].accumulator > scroll.start) {
    b = i
  }
  i = ~~((a + b) / 2)}while(i ! == oldI) i <0 && (i = 0)
startIndex = i
Copy the code

Why can we use this. In computed: Sizes [], item is ranked from small to large in accumulator. So this.sizes is an ordered list.

DynamicScroller. Vue and DynamicScrollerItem.vue code.

See the code we can find that dynamic Roller implementation also depends on RecycleScroller. Vue. The height/width of each item is obtained by dynamicScrollerItem. vue to obtain the size of the array element, and then revert to the corresponding realization of RecycleScroller.

The overall picture looks something like this, which is a little confusing. I hope we can make progress together.

A lot of people resist source code, but it’s a really effective way to learn.