当前位置:网站首页>Understand the principle behind the virtual list, and easily realize the virtual list

Understand the principle behind the virtual list, and easily realize the virtual list

2022-07-28 13:59:00 Maic

In the project , Big data rendering often encounters , such as umy-ui(ux-table) Virtual list table Components ,vue-virtual-scroller as well as react-virtualized These excellent plug-ins quickly meet business needs .

In order to understand the principle and mechanism behind the plug-in , We implement a simple version of our virtual list , I hope it can bring some thinking and help in the actual business project .

Text begins ...

What is a virtual list

In big data rendering , Select a visual area to display the corresponding data .

Let's take a preliminary look at a picture

In this illustration , We can see that what we show is always Red dotted line Part of the show , Each element has a fixed height , By a Very high elements Wrapped in , also Outermost layer There is a fixed height container , And the settings can scroll .

Create a new one index.html The corresponding structure is as follows

...
<div class="vitual-list-wrap" ref="listWrap">
  <div class="content" :style="contentStyle">
    <div class="item" v-for="(item, index) in list"
         :key="index" :style="item.style">
        {{item.content}}
    </div>
  </div>
</div>

Corresponding css

*{
  padding:0px;
  margin: 0px;
}
#app {
  width:300px;
  border: 1px solid #e5e5e5;
}
/* The outer container gives a fixed visual height , And the settings can scroll */
.vitual-list-wrap {
  position: relative;
  height: 800px;
  overflow-y: auto;
}
/* The area of the real container */
.content {
  position: relative;
}
/* Fixed height of each element */
.item {
  height: 60px;
  padding: 10px 5px;
  border-bottom: 1px solid #111;
  position: absolute;
  left:0;
  right: 0;
  line-height: 60px;
}

From the corresponding page structure and css Our thinking is roughly like this

  • Determine the fixed height of the outer layer , And set the vertical scroll bar
  • Relative positioning of real container settings , And dynamically set the height of a loading container according to the displayed total
  • Set absolute positioning for each element , And it is a fixed height

With the corresponding setting structure , Because each of our elements is absolutely positioned , So our current thinking is :

1、 Determine the visible area item The number of bars displayed limit

2、 Current position of sliding up Start bit And Last position , Determine the range of display elements

3、 Determine the top, When sliding up , Determine the current location and the location index of the last element , According to the current position and the last element position , Rendering Visual area

The specific logic code is as follows

<div id="app">
        <h3> Virtual list </h3>
        <div class="vitual-list-wrap" ref="listWrap">
            <div class="content" :style="contentStyle">
                <div class="item" v-for="(item, index) in list" 
                  :key="index" :style="item.style">
                    {{item.content}}
                </div>
            </div>
        </div>
</div>
<!-- introduce vue3 Component library -->
<script src="https://cdn.bootcdn.net/ajax/libs/vue/3.2.33/vue.global.min.js"></script>
<script src="./index.js"></script>

Let's see index.js

  // index.js
const { createApp, reactive, toRefs, computed, onMounted, ref } = Vue;
const vm = createApp({
  setup() {
      const listWrap = ref(null);
      const viewData = reactive({
        list: [],
        total: 1000, //  The total number of data 
        height: 600, //  The height of the viewing area 
        rowHeight: 60, //  Every one of them item Height 
        startIndex: 0, //  initial position 
        endIndex: 0, //  End position 
        timer: false,
        bufferSize: 5 //  Make a buffer 
        
      });
      const contentStyle = computed(() => {
        return {
          height: `${viewData.total * viewData.rowHeight}px`,
          position: 'relative',
        }
      });
      // todo  Set up the data 
      const renderData = () => {
        viewData.list = [];
        const {rowHeight, height, startIndex, total, bufferSize} = viewData;
        //  Of the current viewing area row Number of pieces 
        const limit = Math.ceil(height/rowHeight);
        console.log(limit, '=limit');
        //  The last position of the visible area 
        viewData.endIndex = Math.min(startIndex + limit + bufferSize, total -1);
          for (let i=startIndex; i<viewData.endIndex; i++) {
            viewData.list.push({
            content: i,
            style: {
              top: `${i * rowHeight}px`
            }
          })
        }
      }
      // todo  Monitor rolling , Set up statIndex And endIndex
      const handleScroll = (callback) => {
        // console.log(listWrap.value)
        listWrap.value && listWrap.value.addEventListener('scroll', (e) => {
          if (this.timer) {
            return;
          }
          const { rowHeight, startIndex, bufferSize } = viewData;
          const { scrollTop } = e.target;
          //  Calculate the current scroll position , Get the starting position of the current start 
          const currentIndex = Math.floor(scrollTop / rowHeight); 
          viewData.timer = true;
          // console.log(startIndex, currentIndex);
          //  Do a simple throttling treatment 
          setTimeout(() => {
            viewData.timer = false;
               //  If the sliding position is not the current position 
               if (currentIndex !== startIndex) {
                viewData.startIndex = Math.max(currentIndex - bufferSize, 0);
                callback();
               }
            }, 500)
        })
      }
      onMounted(() => {
        renderData();
        handleScroll(renderData);
      })
      return {
        ...toRefs(viewData),
        contentStyle,
        renderData,
        listWrap
      }
  },
})
vm.mount('#app')

Take a look at the page , already ok 了 , Each up slide will only load the corresponding data at a fixed height

Notice that we are css There's a piece of code like this in

#app {
  width:300px;
  border: 1px solid #e5e5e5;
  opacity: 0;
}
...
[data-v-app]{
  opacity: 1 !important;
}

This processing is mainly used to interpolate expressions when they are not rendered , Let users not see the content of the template before rendering . If you don't hide it first , Then there will be interpolation expressions when the page opens ,vue One is provided in v-cloak, But it doesn't seem to work here , stay vue2 Medium is ok .

This is a very simple virtual list implementation , Understand the implementation idea behind the virtual list , More on that vue-virtual-scroller[1] And react-virtualized[2] Implementation of source code , For specific application examples, please refer to a previous article on partial application The test script crashed the page .

summary

  • Understand what virtual lists are , In big data rendering , Select a visual area to display the corresponding data
  • The principle behind the implementation of virtual lists , The outermost layer is given a fixed height , Then set the vertical Y Axis rolling , Then the parent of each element sets the relative positioning , Set the height of the real display data , according to item Fixed height (rowHeight), According to the visual area and rowHeight Calculate displayable limit number .
  • When the scroll bar slides up , Calculate the rolling distance scrollTop, adopt currentIndex = Math.floor(scrollTop/rowHeight) Calculate the current starting index
  • according to endIndex = Math.min(currentIndex+limit, total-1) Calculate the last index that can be displayed
  • According to the startIndex And end position endIndex, according to startIndex And endIndex Render the visual area
  • Sample code of this article code example[3]
  • This article refers to related articles How to realize a highly adaptive virtual list [4], This is a react Version of

Reference material

[1] vue-virtual-scroller: https://github.com/Akryum/vue-virtual-scroller

[2] react-virtualized: https://github.com/bvaughn/react-virtualized

[3] code example: https://github.com/maicFir/lessonNote/tree/master/javascript/08-%E8%99%9A%E6%8B%9F%E5%88%97%E8%A1%A8

[4] How to realize a highly adaptive virtual list : https://juejin.cn/post/6948011958075392036

原网站

版权声明
本文为[Maic]所创,转载请带上原文链接,感谢
https://yzsam.com/2022/209/202207281247384237.html

随机推荐