Code Monkey home page Code Monkey logo

vue-virtual-scroll-list's Introduction

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.

vue-virtual-scroll-list's People

Contributors

aisin avatar alexanderweiss avatar andriepu avatar chenjigeng avatar dclause avatar dependabot[bot] avatar ellermister avatar fidalgodev avatar gr8den avatar hardlymirage avatar hooooope avatar imwtr avatar korungg avatar kotoriminami avatar leiyunkang7 avatar linniksa avatar mash19 avatar n5leon avatar punkt2 avatar scarry1992 avatar schoonc avatar souljorje avatar stormtv avatar tangbc avatar themeler avatar tiptronic avatar vanishmax avatar xori avatar xxbld avatar youngsx avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

vue-virtual-scroll-list's Issues

how can keep scroll position when unshift items to top?

How can keep scroll position when unshift item in top?

Content starts like:

content top:     -----------
                 B
viewport top:    ===========
                 C
                 D
viewport bottom: ===========

And then a new item is added to the top (A):

content top:     -----------
                 A
viewport top:    ===========
                 B
                 C
viewport bottom: ===========
                 D

Instead of the user continuing to see C at the top of the viewport, C and D have been jarringly pushed down due to the way content typically flows. What we want to happen is:

content top:     -----------
                 A
                 B
viewport top:    ===========
                 C
                 D
viewport bottom: ===========

How it's work with nested items?

I would like to do something like that:

<virtualList :size="50" :remain="20">
	<draggable v-model="items" @start="drag=true" @end="drag=false">
		<item v-for="(item, index) of items" :item="item" :key="item.id" :index="index"/>
	</draggable>
</virtualList>

how can i do that? help me plz

Alternating background CSS (e.g. tables) switches randomly

I have a CSS table colouring as follows:

.striped:nth-child(odd) {
	background-color:#D7ECF3;
}
.striped:nth-child(even) {
	background-color:#f5fbfb;
}

and the table shows up fine, however when scrolling, my guess is occasionally it adds 1 or 2 rows causing this kind of behaviour. I added a gif showing the behaviour (watch the background of the highlighted row)

Perhaps instead of adding (or removing) exact number of rows at the top, always add the same number?

jumps

[suggestion] Sorting ?

Thanks for your great work! Is it possible add sorting function to the item at infinite data? By default, need set a max value for the item then sort it.

Is there any way to use this component with items that the height is not known ?

I have read the docs and it clearly stated that the height of the items needs to be know.

But I like to ask you directly, if there is any way, to use this component with items that the height cannot be known in advanced ?

The problem is that I am showing a book with chapters. Each chapter is shown in a card paragraph, but the height is not known. The book may have up to 2000 chapters. (each chapter is not longer then few sentences)

Rendering 2000 chapters takes up to 10-15 sec and freezes the browser. I do not like to use pagination, so I was thinking to use the virtual scroll. But the problem is that I do not know the height of the chapter in advanced because it can vary based on the text and also based on the view pot width.

So my question is, is there any way to use this component with items that the height is not know ? Maybe I can calculate the height run time ?

bugs in variable height mode

As i see from your guide, in variable height mode for this component, we need to pass prop variable as a function (or boolean) to it, but for your example, you just know all the item's height before you render it(or before they get inserted into DOM tree), so you can get right calculation. But in most cases, we don't know how height the item is before it was inserted into DOM tree, then how could i get that height and return it from function variable as what you did here Actually i tried as follows:

getVariableHeight (index) {
                var instance = null;
                var dom = null;
                var height = 0;
                if (instance = this.$refs.vsl.$slots.default[index].componentInstance) {
                    dom = instance.$el;
                    height = dom.getBoundingClientRect().height;
                }
                return height;
            }

The above getVariableHeightfunction also comes from above link, but i rewrote it to meet my scenario. But it does not work. Can you please tell me what is the best practice in my situation?

Set scroll position to end of list

We would like to use the virtual list like in a window which is similar to linux tail command. We would like the scroll to be positioned at the bottom of the window by default.
We tried to use :start and :offset with no success.
Can you please advise if this is possible and how?

Table with headers

Any idea how we can implement a <table> with <thead>?

<template>
    <table>
        <thead>
            <tr>
                <th v-for="column in columns">{{ column.title }}</th>
            </tr>
        </thead>
         <virtualList rtag="div" :size="62" :remain="20" wtag="tbody"> 
            <tr :key="item.id" v-for="(item, index) in items">
                <td v-for="column in columns">{{ item[column.field] }}</td>
            </tr>
         </virtualList>
    </table>
</template>

This throws a <div> between <tbody> and <table> messing up the layout.

麻烦问下作者,virtual-list的高度必须是固定的吗?

我的需求是表格高度和页面高度一样,但是浏览器页面高度是不确定的,所有需要设置容器高度为100%。我设置virtual-list的高度为100%情况下,v-for循环的元素是全量渲染的,请问这样的效果没办法做到吗

Add a function to be called when forceUpdate

It would be great if we can call a function everytime we call this.$forceUpdate() inside updateZone function.

Then, my itens can know if they came from scroll event or from outside.

I need this because I change the CSS class based on origin.

Fixed column

Hello! Nice plugin!

I was wondering if it is possible to have a fixed column to the left right this example http://jsfiddle.net/4kpzN/437/ with the current functionality.

I cannot achieve the same result due to the "display: block" that the plugin force attaches to the wrapper div.

Thanks in advance.

Animation on start change?

Hi, thanks for your plugin, is great.

I was wondering if there's an easy way to add some kind of animation when mutating start prop. I'm scrolling when clicking some button, and I want the list to smoothly scroll to the element.

I tried adding animation: all ease 0.3s; to the virtual-list item wrapper element class, but with no luck.

Thanks!

Multiple column flex layout

Hey, so after a lot of tweaking and hacking, I put together this codepen.
https://codepen.io/daniandl/pen/opZGMd?editors=1010

How it is right now is already very good, this is the only lib I got this far in, but when you do 1 scroll tick (very slight scroll to just trigger 1 dom node recycle), you can see that the 7 jumps to 30 (depends on your window size). When scrolling back up though, it cycles through the numbers one by one. That would be what I'm trying to achieve.

Its not like the 31 wasn't in the screen before, so the user could see it... but what could i change to improve this?

Thanks, great lib!

Display problems in multi list switching

I have two lists (short-list & long-list) that need to be displayed, and I encountered a display problem when I was switching them.

Demo: https://jsfiddle.net/aisin/7y8h2q1k/3/

How to recurrence:

  • At first, SHORT-list will be displayed.
  • click show LONG-list button to display it.
  • Scroll down at least more than 3 items.
  • click show SHORT-list button.
  • click show LONG-list button.

Now, You should see only the first 6 items are displayed, until scrolling down you can see all of them.
How to support the correct display of multi list switching?

Variable height of virtual-list component + Infinite Scrolling

In my case, the virtual-list component fits the entire window height. So, its height changes if the monitor resolution changes.

I know the item height exactly, but I don't know how to use the props correctly to call the tobottom function.

How can I solve this?

使用时Chrome中报错“Vue2.component is not a function”

Uncaught TypeError: Vue2.component is not a function
    at eval (eval at <anonymous> (app.js:1011), <anonymous>:14:17)
    at eval (eval at <anonymous> (app.js:1011), <anonymous>:3:26)
    at eval (eval at <anonymous> (app.js:1011), <anonymous>:11:3)
    at Object.<anonymous> (app.js:1011)
    at __webpack_require__ (app.js:660)
    at fn (app.js:86)
    at eval (eval at <anonymous> (app.js:819), <anonymous>:4:82)
    at Object.<anonymous> (app.js:819)
    at __webpack_require__ (app.js:660)
    at fn (app.js:86)

Vue:2.3.4

variable list content size?

Is there a way to not specify the item height? We are loading a lot of items with a different content size which essentially means different item heights.

As the ag-grid component explains here https://www.ag-grid.com/javascript-grid-row-height/?framework=vue#gsc.tab=0, You cannot use variable row height when doing virtual paging or viewport. This is because these row models need to work out the position of rows that are not loaded and hence need to assume the row height is fixed. They use getRowHeight() callback, wondering if we can use something similar here?

如何重置virtual-scroll-list?

qq 20170921101638

如图所示,通过Tab切换显示三个VirtualList时,会出现这种情况。
如何能实现每次切换的时候,重置VirtualList的padding样式,使之能恢复最初的加载状态?

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!

Handle dynamic lists

Use case is when list length changes after mount.
i.e. remain and bench are updated.

Fixed this locally by setting watchers for remain and bench properties, and then executing the delta initialization that's done in beforeMount

p.s. thanks for the great component, it's a real life saver.

inline style

Please add
inline style to pass as prop.
I need to pass display:table, instead display:block
Thanks

[help] can you give me an example about onscroll function?

Can I use the onscroll function to get the users scrolling index? I thinking to bookmark the row index, so the user can starts where they left. In my case, the user may scroll the virtual scroll list until a certain row of data, then the user will navigate to another page when the user returns back to the virtual scroll list page, the data will start from index 0 again. Can you guide me how to make a bookmark about this?

start 对于边界条件的BUG

  1. 当列表项少于 remain 时,滚动到 start 设置后会使上方列表项蜜汁空白。
  2. start 数值 为负或者大于列表项长度时的 overflow ,建议增加容错机制。比如为负就认为是0,过大就认为是最后一项就好。

问题1的示例代码:

<template>
  <div>
    <VirtualList id="sss" :start=startPos :size="50" :remain="6" class="list" :onScroll="scrollTest" ref="scrollArea">
      <div class="item" v-for="(udf, index) of items" :index="index" :key="index">
        <span>Item # {{ index }}</span>
      </div>
    </VirtualList>
    <Button @click="toScrollTest">Test</Button>
  </div>
</template>
<script>
  import VirtualList from 'vue-virtual-scroll-list'
  export default {
    name: 'finite-test',
    components: { VirtualList },
    data () {
      return {
        items: new Array(3),
        startPos: 0
      }
    },
    methods: {
      scrollTest (e, scrollTop) {
        console.log('发生滚动')
        console.log(e)
        console.log(scrollTop)
      },
      toScrollTest () {
        this.startPos = 1
      }
    }
  }
</script>
<style scoped>
  .list {
    border-radius: 3px;
    border: 1px solid #ddd;
    -webkit-overflow-scrolling: touch;
    overflow-scrolling: touch;
  }
  .item {
    height: 50px;
    line-height: 50px;
    padding-left: 20px;
    border-bottom: 1px solid #eee;
  }
</style>

Recover position with insert in head list

Demo https://codesandbox.io/s/4qq3y7nq1x

I want insert chunks in head of list (when :totop triggered) and recover position to "unread messages". I'm trying to do this through an assignment :start props to received chunk length. But this work only one time, because length chunks do not change, and :stop watcher do not triggering changes (is the same number).

Easier-to-use variable height API

This is a great library! Really smart architecture.

With mixed lists & complex UIs, it's not always the easiest thing to just spell out the heights of the items individually (mixing in group headers, etc). Fortunately, your basic structure doesn't require that! What works better for me, is to set an explicit style on each item that announces the height (i.e. <h1 style="height: 30px">Some Header</h1>), and then rewire the getVarSize thusly:

    // return a variable size (height) from given index.
    getVarSize: function (index, nocache) {
      var cache = this.delta.varCache[index]
      const get = (index) => {
        var item = this.$slots.default[index];
        if(item.data.staticStyle && item.data.staticStyle.height) {
          var m = item.data.staticStyle.height.match(/^(.*)px$/);
          return Number(m[1]);
        }
        
        return Number(item.data.attrs.height);
      }
      return (!nocache && cache && cache.size) || get(index) || 0
    },

If I were to push this as a PR, I'd make it so it does this if variable is set to true, and retain the original behavior if it's a function. Thoughts?

Checkbox state refreshes on scroll

Hi, I am using this plugin to display list with checkboxes.

But the state of checkbox is lost when scrolling down and scrolling back up.

Can you tell me how can I fix this?

Problem with flex design

Just saw that the wrapper div and root div bind with style (display: block). I think it would be better if we use classes instead of style for those who wants to make alignments in box style.

Empty wtag

Can you make the wtag optional and leave the styling to the user? The problem I have is with tables, where the rtag would be the tbody and wtag the tr. For the tr I'm using my own component and I don't require the wrapper element, because I can style the component myself. Leaving the wtag attribute empty does not work as is though.

[questions] full-text search?

Is it possible have a full-text search function? I thinking to search some data from the list. Can you suggest me some ways to achieve that?

Use another container tag

I'd like to use this library within a <table>, so I'd like the parent element to be a <tbody>. But it appears it's hardcoded to use a <div>. Unless I'm overlooking something?

visible elements

Hi!

I'm using your library and I like it very much, but
don't know how to get the list of visible elements.

I have a page with a large number of virtual lists.

Have tried to use some ready libraries. They are bind to the scrolling of the main window and do not work with the virtual list.

The libraries I have seen do not offer the possibility to call the function compulsory visibility calculation (maybe I did not see), otherwise I would have tried it in the event onscroll.

Do you have any ideas?
I hope your answer, thank you.

Dynamic content loading.

Looking at your documentation, there does not seem to be any way to support dynamically loaded content, where the total number of items is know at the start, but the actual information needs to be loaded just before it is shown.

Bascially I have an array of IDs, and just before the item is shown I need to load the actual information from the DB.

Basically I need the list to call a function every time it needs new data. Is there a way to supply a per-element rendering callback or some such? (For example: the way this library does it)

Re-calculate padding when slots change

When filtering, I noticed that the dimensions of the scroll container aren’t updated which leads to overshoot scrolling. I’m not sure if this is a general misbehavior or related to my specific case.

overflow

I’m working on fixing this, by adding the updated life cycle method to the component. If the number of slots changed, padding recalculations similar to the ones on updateZone might be necessary. In my case, I also want to force scrollTop = 0 when filtering to make sure that the results are in the viewport. I’m not done, but I’m curious to hear if you can confirm this issue.

Isolation of the issue:
https://codepen.io/getflourish/pen/xLxaWG

无法捕获"onScroll"滚动事件

代码:

<template>
  <div>
    <VirtualList :size="50" :remain="6" class="list" @onScroll="scrollTest">
      <div class="item" v-for="(udf, index) of items" :index="index" :key="index">
        <span>Item # {{ index }}</span>
      </div>
    </VirtualList>
  </div>
</template>
<script>
  import VirtualList from 'vue-virtual-scroll-list'
  export default {
    name: 'finite-test',
    components: { VirtualList },
    data () {
      return {
        items: new Array(100000)
      }
    },
    methods: {
      scrollTest (e, scrollTop) {
        console.log('发生滚动')
        console.log(e)
        console.log(scrollTop)
      }
    }
  }
</script>
<style scoped>
  .list {
    border-radius: 3px;
    border: 1px solid #ddd;
    -webkit-overflow-scrolling: touch;
    overflow-scrolling: touch;
  }
  .item {
    height: 50px;
    line-height: 50px;
    padding-left: 20px;
    border-bottom: 1px solid #eee;
  }
</style>

我监听了 VirtualList 的 onScroll 事件,事件却捕获不到,在 Vue DevTools 中也只能看到 onTop 和 onBottom 而没有 onScroll 。
Vue Version: 2.3.4

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.