⚡️A vue component support big amount data list with high render performance and efficient.

Overview

CIStatus Downloads Version Quality

Table of contents

Advantages

  • Only 3 required props, simple and very easy to use.

  • Big data list with high render performance and efficient.

  • You don't have to care about item size, it will calculate automatic.

Live demo

https://tangbc.github.io/vue-virtual-scroll-list

https://codesandbox.io/s/live-demo-virtual-list-e1ww1

Simple usage

npm install vue-virtual-scroll-list --save

Root component:

<template>
  <div>
    <virtual-list style="height: 360px; overflow-y: auto;" // make list scrollable
      :data-key="'uid'"
      :data-sources="items"
      :data-component="itemComponent"
    />
  </div>
</template>

<script>
  import Item from './Item'
  import VirtualList from 'vue-virtual-scroll-list'

  export default {
    name: 'root',
    data () {
      return {
        itemComponent: Item,
        items: [{uid: 'unique_1', text: 'abc'}, {uid: 'unique_2', text: 'xyz'}, ...]
      }
    },
    components: { 'virtual-list': VirtualList }
  }
</script>

Item component:

<template>
  <div>{{ index }} - {{ source.text }}</div>
</template>

<script>
  export default {
    name: 'item-component',
    props: {
      index: { // index of current item
        type: Number
      },
      source: { // here is: {uid: 'unique_1', text: 'abc'}
        type: Object,
        default () {
          return {}
        }
      }
    }
  }
</script>

More usages or getting start you can refer to these clearly examples.

Props type

Required props

             Prop              Type Description
data-key String|Function The unique key get from data-sources in each data object. Or a function called with each data-source and return their unique key. Its value must be unique in data-sources, it is used for identifying item size.
data-sources Array[Object] The source array built for list, each array data must be an object and has an unique key get or generate for data-key property.
data-component Component The render item component created / declared by vue, and it will use the data object in data-sources as render prop and named: source.

Optional props

Commonly used

           Prop            Type Default Description
keeps Number 30 How many items you are expecting the virtual list to keep rendering in the real dom.
extra-props Object {} Extra props assign to item component that are not in data-sources. Notice: index and source are both occupied inner.
estimate-size Number 50 The estimate size of each item, if it is closer to the average size, the scrollbar length looks more accurately. It is recommended to assign the average that calculate by yourself.
Uncommonly used

               Prop                Type Default Description
start Number 0 Setting scroll position stay start index.
offset Number 0 Setting scroll position stay offset.
scroll Event Emited when scrolling, param (event, range).
totop Event Emited when scrolled to top or left, no param.
tobottom Event Emited when scrolled to bottom or right, no param.
resized Event Emited when item resized (mounted), param (id, size).
direction String vertical Scroll direction, available values are vertical and horizontal
page-mode Boolean false Let virtual list using global document to scroll through the list.
top-threshold Number 0 The threshold to emit totop event, attention to multiple calls.
bottom-threshold Number 0 The threshold to emit tobottom event, attention to multiple calls.
root-tag String div Root element tag name.
wrap-tag String div List wrapper element (role=group) tag name.
wrap-class String List wrapper element class name.
wrap-style Object {} List wrapper element inline style.
item-tag String div Item wrapper element (role=item) tag name.
item-class String Item wrapper element class name.
item-class-add Function A function that you can return extra class (String) to item wrapper element, param (index).
item-style Object {} Item wrapper element inline style.
item-scoped-slots Object {} The $scopedSlots for item component.
header-tag String div For using header slot, header slot wrapper element (role=header) tag name.
header-class String For using header slot, header slot wrapper element class name.
header-style Object {} For using header slot, header slot wrapper element inline style.
footer-tag String div For using footer slot, footer slot wrapper element (role=footer) tag name.
footer-class String For using footer slot, footer slot wrapper element class name.
footer-style Object {} For using using footer slot, footer slot wrapper element inline style.

Public methods

Usefull public methods

You can call these methods via ref:

Method Description
reset() Reset all state back to initial.
scrollToBottom() Manual set scroll position to bottom.
scrollToIndex(index) Manual set scroll position to a designated index.
scrollToOffset(offset) Manual set scroll position to a designated offset.
getSize(id) Get the designated item size by id (from data-key value).
getSizes() Get the total number of stored (rendered) items.
getOffset() Get current scroll offset.
getClientSize() Get wrapper element client viewport size (width or height).
getScrollSize() Get all scroll size (scrollHeight or scrollWidth).
updatePageModeFront() When using page mode and virtual list root element offsetTop or offsetLeft change, you need call this method manually.

Attentions

This component use an in-place patch strategy to render list instead of v-for and :key. This way achieves the best efficient, but only suitable when your list output does not rely on item component inner state or temporary DOM state (e.g. form input values).

But how to deal with such a situation? Without maintaining inner state, recommend to use props and dispatch (stateless component), here is an example keep-state.

Contributions

Welcome to improve this component with any issue, pull request or code review.

Changelogs

Maintain and update occasionally, for changes see release.

License

MIT License.

Issues
  • Perfomance slow down in empty vue-cli project

    Perfomance slow down in empty vue-cli project

    Hello, I`m using your scroll-list and it's an awesome lib, but I see the perfomance slow down when I'm trying your examples in blank vue-cli project. Maybe you know what I am doing wrong? All code in new project is code of your item-mode example. my example

    question 
    opened by scarry1992 21
  • Occasional blank rows

    Occasional blank rows

    Occasionally I see the rows as blank until I manually scroll. A coworker has noticed the same thing where all the initial items were not visible until scroll. He was in Safari and I am in Chrome. Might there be a case where a redraw is not caused? If its related, I also am calling scrollToBottom when items are added.

    bug 
    opened by smakinson 20
  • when list is embedded in a tab, it sometimes crashes

    when list is embedded in a tab, it sometimes crashes

    Thanks for the list code, it's very helpful!

    I had a problem while using the list in a tab view. When I tried to move from another tab to this one, sometimes the list crashed in setScrollTop (something like: can't set attribute 'scrollTop' to an undefined object) Can you add something like:

    // set manual scroll top. setScrollTop: function (scrollTop) { if (!this.$refs || !this.$refs.vsl) return;

                this.$refs.vsl.scrollTop = scrollTop
            },
    

    I think that this is also necessary in onScroll

    Thanks!

    bug 
    opened by sigalalg1 18
  • Padding offset could be updated

    Padding offset could be updated

    Hi @tangbc your new release 2.x rocks! I've used your previous 1.x and now this is a big step forward! I tried to update my previous component with this new version, but I see a strange behavior on scrolling (see blow).

    Description

    The padding of the virtual component (role = group) containing all items (keeps) is updated to a new value that places the first item to the top of the viewport: see image 1 (before the trigger on scroll) and image 2 (after the trigger).

    Image 1

    image1

    Image 2

    image2

    I think that after the first initial scroll, the padding should be computed to repositioning the items like you see in the Image 3, triggering a new value update when the first visible item has scrolled to the trigger positions (red arrows). In this way when the list is scrolled up or down, some items are available to render. The same behavior should be applied to the horizontal items.

    Image 3

    VueVirtualScroller

    Image 4

    Image4

    Demo

    Below the render problem using functional components as items (stateless). The image 4 shows an item structure example. I tried to increase the keeps prop's value, but this only helps the scroll down behavior (not the scroll up's one). The behavior is still the same using 1.000 or 100.000 items.

    VueVirtualScroller

    Other

    • Version: 2.0.9
    • Browser: Chrome (see the video) and Safari (in this case the scroll is jerky on padding update)

    Thank you. All the best!

    bug 
    opened by mgesmundo 15
  • Add props page-mode

    Add props page-mode

    Could not restore scroll position using scrollBehavior of vue-router. Therefore, we added pageMode to change the scroll target to "window".

    opened by amatakasap 12
  • Jumps in scrolling

    Jumps in scrolling

    When i scroll the library with the mouse, then the scroll sometimes jumps and scrolls a larger number of rows in the list. (It jumps both scrolling up and scrolling down, at certain points in the list, even though there is nothing special about these items in the list). The problem was with version 1, and now I have upgraded to the latest version (2.3.2) and the problem still exists. Has anyone encountered such a problem and can direct me to a solution? Thanks.

    question 
    opened by chgold 12
  • Support of grid (multiple items in row)

    Support of grid (multiple items in row)

    Hello, library is amazing, but I need the support of multiple items in the single line, did you considering this?

    suggestion 
    opened by drozdzynski 12
  • Dynamic data update in [data-sources]

    Dynamic data update in [data-sources]

    Hi, I have a question, how does your tool automatically update data? The data that was presented in data-sources?

    I do a chat, and when a new message appears in the chat, the array update is not passed through props.

    Maybe I don't understand something, I apologize in advance.

    question 
    opened by libid0nes 12
  • 列表中滚动到最后一页会发现概率性缺失,range计算错误

    列表中滚动到最后一页会发现概率性缺失,range计算错误

    Describe

    通过下拉混动条、事件scrollToBottom、手动滚动到底部过程中会出现页面下半部分白屏现象,当滚动到最底部时会有几条数据没展示(其中手动滑轮滚动的缺失条数每次不一样,下拉滚动条和事件触发都是恒定n条,其中Mac和window下试过不一样,Mac通过事件是能展示全的)

    To Reproduce

    <virtual-list
          ref="listWrapper"
          style="height: 600px;"
          class="scroll-wrapper"
          :data-key="'value'"
          :data-sources="lists"
          :data-component="itemComponent"
          :estimate-size="18"
        ></virtual-list>
    

    下面是itemComponent

    <template>
      <el-checkbox
        :label="source.value"
        :key="source.value"
        :value="source.checked"
        @change="changeCheck"
      >{{ source.value }}</el-checkbox>
    </template>
    

    最后一页的时候data中range计算值为(实际上有1000条数据) {"start":967,"end":996,"padFront":17426,"padBehind":54}

    version

    list:v2.2.8 vue: v2.6.11 chrome: 83.0.4103.97

    bug 
    opened by youzime 11
  • insert `thead` into table

    insert `thead` into table

    Hi. First of all I want to thank you for this module, it works really well. I'm facing with little problem. The code below is rendering table. The table has tbody tag, but also i'd like to have thead tag in the table. Please advise how can I insert thead with its th in the table, if it's possible of course. Thank you.

    <virtual-list :size="20" :remain="10" rtag="table" wtag="tbody" > <tr v-for="(row, ir) in sheet" :key="ir" > <td>{{ +ir + 1 }}</td> <td v-for="(cell, ic) of row" :key="'c' + (ic + 1) + 'r' + (ir + 1)" v-html="cellDisplayValue(ir + 1, ic + 1)" > </td> </tr> </virtual-list>

    enhancement 
    opened by luman-web 11
  • How to add keyup or keydown events to the virtual scroller? Programmatically or on template?

    How to add keyup or keydown events to the virtual scroller? Programmatically or on template?

    • I apologize for this question, it is already referenced in
    • #89
    • #152
    • #329
    • but none of the issues show how and where they are adding this
    • I tried adding @keydown to the virtual list but the event is not fired
    
      <virtual-list
        :style="style"
        scrollable
        :data-key="'uid'"
        :data-sources="items"
        :data-component="itemComponent"
        :footer-class="'loader-wrapper'"
        v-on:tobottom="onScrollToBottom"
        @keydown='onKeyDown'
      >
        <div slot="footer" class="loader"></div>
      </virtual-list>
    

    I basically want to use the arrow keys to scroll up and down instead of the scrollbar. How do I achieve this with the virtual scroll list?

    question 
    opened by slidenerd 0
  • When the list of elements in DOM is updated on scrolling, happening blink or jump lag. How it fixed?

    When the list of elements in DOM is updated on scrolling, happening blink or jump lag. How it fixed?

    I faced a similar problem as in this #294 or this #291 post. But the solutions available there did not help me, or I did not fully understand them.

    I have a list with items. They are of fixed height. When the list comes to an end and the virtual-scroll-list creates a new one, an unpleasant jump (twitch) occurs.

    It's component with virtual-scroll:

    <template>
      <div class="virtualListWrap" id="virtualListForMap">
        <p v-if="err">
          Что-то пошло не так =(
        </p>
    
        <p v-else-if="offers === 'no-result'">
          Результатов нет!
        </p>
    
        <template v-if="offers !== 'no-result'">
          <virtual-list
            class="list-infinite customScroll"
            @scroll="scrollHandler"
            :data-key="'id'"
            :data-sources="offers"
            :data-component="itemComponent"
            :estimate-size="140"
            :keeps="40"
            ref="offersForMap"
          />
        </template>
      </div>
    </template>
    
    <script>
    import OfferMapItem from "./OfferMapItem.vue";
    
    import eventBus from "../../services/eventBus.js";
    
    export default {
      props: ["offers", "err"],
    
      data() {
        return {
          itemComponent: OfferMapItem,
          chosenId: null
        };
      },
    
    //...
    

    It's item component:

    <template>
      <div class="offer-mini-item" :id="'offer-mini-item-' + source.id" :data-index="source.position">
    
        <div class="offer-mini-item__thumb" v-if="source.photo === 'no-photos'">
          <img src="/public/images/no-image.png" alt="квартира" />
        </div>
    
        <div class="offer-mini-item__thumb" v-else>
          <img :src="'http://fur.ru' + source.photo" alt="квартира" />
        </div>
    
        <div class="offer-mini-item__content">
          <div class="f-1">
            <div class="offer-mini-item__title" v-html="source.title"></div>
    
            <div class="offer-mini-item__builder" v-if="source.price < 7000000">
                <i class="f-icon f-icon-secondary"></i>
                <span>Вторичка</span>
            </div>
    
            <div class="offer-mini-item__builder" v-else>
                <i class="f-icon f-icon-newBuilding"></i>
                <span>Новостройка</span>
            </div>
    
            <div class="d-flex jus-sb align-center">
              <div class="offer-mini-item__price">{{ new Intl.NumberFormat('ru-RU').format(source.price) }} ₽</div>
              <div class="offer-mini-item__barg">Возможен торг</div>
            </div>
          </div>
          <a :href="'/offers/' + source.link" class="offer-mini-item__more-btn" target="_blank">Подробнее</a>
        </div>
      </div>
    </template>
    
    <script>
    export default {
      props: {
        source: {
          type: Object,
          default() {
            return {};
          }
        }
      }
    };
    </script>
    

    What could be the problem?

    Thanks.

    question 
    opened by tampambro 0
  • Question: Nested elements

    Question: Nested elements

    Hi. Is it possible to use this package for nested elements? Component's template is something like this comment-item.vue:

    <template>
      <div>
        <!-- some text -->
         
        <comment-item v-for="child in children" :key="child.id" :data="child">
      </div>
    </template>
    

    And page template:

    <template>
        <comment-item v-for="comment in rootComments" :key="comment.id" :data="comment">
    </template>
    
    opened by arkhamvm 0
  • Mobile scrolling with page-mode doesn't render past

    Mobile scrolling with page-mode doesn't render past "keeps" items

    Describe

    When using a mouse wheel to scroll on MacOS, the virtual scroll works as intended in page-mode. However, when testing on a physical iOS device and Chrome mobile simulators, the virtual list only renders the amount of items set by :keeps. For example, if :keeps is set to 20, the page will render 20 items despite the list being greater than 20, and then there will be a ton of whitespace beneath the rendered components.

    To Reproduce

    Steps to reproduce the behavior:

    1. Use page-mode, populate list items greater than the :keeps prop.
    2. My component looks like this:
    <virtual-list
                ref="itemList"
                class="scroll-touch"
                data-key="id" :keeps="20"
                :page-mode="true"
                :estimate-size="355"
                :data-sources="items"
                :data-component="component"
              />
    

    .scroll-touch was taken from the page mode example. 3. Run on a mobile phone or mobile simulator, and scroll past the number of items defined by :keeps.

    Other

    • Version 2.3.2
    • iOS Chrome and Safari
    • MacOS Safari
    bug 
    opened by allynsweet 0
  • [Feature Request] Provide way to use a scroll target

    [Feature Request] Provide way to use a scroll target

    Describe the feature request

    Provide a way to specify a scroll target, such as a specific element that we are scrolling on.

    Why?

    An example of how/why can be found with the Quasar framework: https://quasar.dev/vue-components/virtual-scroll#scroll-target

    suggestion 
    opened by douglasg14b 0
  • add item slot

    add item slot

    What kind of this PR? (check at least one)

    • [ ] Bugfix
    • [x] Feature
    • [ ] Code style update
    • [ ] Build-related changes
    • [ ] Other, please describe:

    Other information: support item slot api

    opened by Ljsxx 0
  • Navigation

    Navigation

    Good day! How can I navigate through list items or component items using the keyboard? At the moment the keyboard arrows are handling the scroll event, me need to cancel this behavior and move the focus to another item in the list.

    question 
    opened by ddenis87 3
  • support drop and select

    support drop and select

    Describe the feature request

    Is it possible to support drag and drop selection? This is a great feature.

    Since it is a virtual node, I am not sure how to implement it.

    是否有可能支持拖拽选择?这是一个很棒的功能。 由于是虚拟的节点,所以我也不确定如何去实现它

    https://user-images.githubusercontent.com/9758711/115982378-1a1e3c80-a5cd-11eb-8b1f-a959b80f071f.mov

    suggestion 
    opened by axetroy 0
  • Why is data-key needed?

    Why is data-key needed?

    Thanks for this library. It is well done.

    I have a question on design. Why is the data-key needed?

    you said this

    it is used for identifying item size.

    I was just wondering if this was the only reason. It is a little difficult i think that the data needs to always have this when it is unnecessary (from the data's end).

    Is there a way to assign some default ID for data that does not have force someone to change to data in order to use the library?

    I am thinking that it might be better if there was an option if the component asked for the key on each iteration. This was, I can provide some arbituary ID instead of modufying the data. What are your thoughts?

    question 
    opened by patchthecode 0
  • How to measure the performance of virtual scrolling in a production environment?

    How to measure the performance of virtual scrolling in a production environment?

    In fact, I can view the local performance through the FPS tool in devtools. But how do I know the actual performance of users in the production environment

    question 
    opened by lwxsanshui 0
Releases(v2.3.2)
⚡️ Blazing fast scrolling for any amount of data

vue-virtual-scroller Blazing fast scrolling of any amount of data | Live demo | Video demo Sponsors Table of contents Installation Usage RecycleScroll

Guillaume Chau 5.9k Jul 23, 2021
A pure vue native horizontal list implementation for mobile/touch and responsive web.

?? You might want to use Vue Horizontal instead! Vue Horizontal is another take on the horizontal layout written by me with an ultra simple implementa

Fuxing Loh 115 Jul 19, 2021
Official Vue.js wrapper for fullPage.js http://alvarotrigo.com/vue-fullpage/

Vue-fullpage.js Official Vue.js wrapper for the fullpage.js library. Demo online | Codepen fullpage.js Extensions By @imac2. Thanks to VasiliyGryaznoy

Álvaro 1.6k Jul 23, 2021
Vue component for efficiently rendering large collection data

vue-virtual-collection Vue component for efficiently rendering large collection data. Inspired by react-virtualize. Demo Table of Contents generated w

Weijia Wang 536 Jul 20, 2021
Vue.js Masonry layout component powered by CSS, dependancy free

A new masonry component powered by CSS to be fast loading and free of jQuery or other dependencies. Build specifically for Vue.js projects. ?? Why? Ex

Paul Collett 402 Jul 20, 2021
The Ultimate fully-customizable plugin for skeleton cards in Vue. It's a no-brainer.

The Ultimate fully-customizable plugin for skeleton cards in Vue. It's a no-brainer.

Neelansh Mathur 67 Jul 14, 2021
💠 Vue.js directive for masonry blocks layouting ✅

vue-masonry Current version: 0.12.0 Vue.js directive for masonry blocks layouting. Original masonry library. Plugin DEMO available ?? , JSFiddle DEMO

Mikhail Kuznetcov 530 Jul 20, 2021
A vue layout component to provide dynamic, reactive media query information

Vue-Breakpoint A vue layout component to provide dynamic, reactive media query information. Uses the match media api.

Alex Regan 9 Jan 2, 2020
Vue smarter layout components. Based on css flexbox. Support responsive design, server side render. 5 KB gzipped.

vue-colrow Smarter layout components. Based on css flexbox. Support responsive design, server side render. 3 KB gzipped. Document. It also has a React

Xinxin 6 Apr 21, 2021
A tiny Drawer component with bounced animation for Vue 🚪🎏🗄🔛

vue-simple-drawer TODO remove shadow for default style add cover layer option rename the scss vars nest drawer? Install npm install vue-simple-drawer

Vincent Guo 54 Jun 19, 2021
A reusable flexbox component using functional css and functional Vue components.

vue-flex A Vue.js functional component to wrap anything in flexbox. (1.8kb gzipped js+css, or 1.2k js & .6k css) Getting Started import Vue from "vue"

Alex Regan 61 Mar 1, 2021
:iphone: Vue component for isotope filter & sort magical layouts

Vue.Isotope Vue component (Vue.js 2.0) or directive (Vue.js 1.0) allowing isotope layout including filtering and sorting. Motivation Integrate Vue wit

David Desmaisons 331 Jun 28, 2021
A pure vue responsive masonry layout without direct dom manipulation and ssr support.

vue-masonry-wall A pure vue responsive masonry implementation without direct dom manipulation, ssr friendly with lazy appending. I created this becaus

Fuxing Loh 117 Jul 22, 2021
A simple Vue blog template that displays posts from any WordPress REST API endpoint.

WP Vue This is just a simple Vue application (scaffolded using the Vue CLI) that pulls posts from a WordPress REST API endpoint. Clone or fork this su

Alex MacArthur 437 Jul 13, 2021