svelte-virtual-list icon indicating copy to clipboard operation
svelte-virtual-list copied to clipboard

Support multiple items per row

Open boutros opened this issue 6 years ago • 5 comments

It would be great if this also could support multiple items per row, to enable grid-like views.

Would you be interested in expanding VirtualList to take an itemsPerRow parameter?

<VirtualList items={items} itemsPerRow={3} />

boutros avatar Jun 29 '18 06:06 boutros

Any progress on this? Maybe not from Rich.

japgun avatar Jan 09 '20 15:01 japgun

I found it was quite simple to create a regular CSS grid and simply place an IntersectionObserver below it that adds additional items to the grid every time it intersects the viewport. See here for a working implementation: https://studenten-bilden-schueler.de/blog (source). Would look something like this:

<script>
  import PostPreview from './components/PostPreview.svelte'
  import IntersectionObserver from './components/IntersectionObserver.svelte'

  export let posts

  let activeTag
  let nVisible = 9
  const onIntersect = () => (nVisible += 6)

  $: visiblePosts = posts.slice(0, nVisible)
</script>

<ul>
  {#each visiblePosts as post (post.slug)}
    <PostPreview {post} />
  {/each}
</ul>
<IntersectionObserver on:intersect={onIntersect} top={400} />

<style>
  ul {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(18em, 1fr));
    gap: 1em;
  }
</style>

janosh avatar Jan 13 '21 07:01 janosh

@boutros and @japgun I came up with a little solution whereby I output 6 items from my array in each virtual list row and control those with css grid. Looks a bit mad i'll admit but does work and is performant. If you want more than 6 on a virtual list row container then change everywhere it says 6

<VirtualList height="100vh" {items} let:item>
   <div class="row">
      <!-- loop for items in each row, that references 0..5, then 6..11 etc -->
      {#each Array(6) as _, i}
         {#if data[item * 6 + i]}
            {data[item * 6 + i].name}
         {/if}
      {/each}
   </div>
</VirtualList>

<script>
   import VirtualList from '@sveltejs/svelte-virtual-list'

   // Array of data to display in virtual list
   export let data
   
   // New array that contains numbers 1..n
   // Dividing the data array length by 6 as there are 6 items per row
   let items = [...Array(Math.ceil(data.length / 6)).keys()]
</script>

<style lang="scss">
   .row {
      display: grid;
      gap: 1rem;
      /* change the number in the repeat to control items per line */
      grid-template-columns: repeat(3, minmax(0, 1fr));
   }
</style>

mattpilott avatar Jan 19 '21 19:01 mattpilott

How would you possibly pass a component here? the below doesn't work

<VirtualList height="100vh" {items} bind:start bind:end let:item>
          <ItemCard product={item}/>
 </VirtualList>

blazzjosh avatar Aug 23 '21 10:08 blazzjosh

@blazzjosh if you are implementing my example you'll need to wrap your ItemCard like so:

<VirtualList height="100vh" {items} let:item>
   <div class="row">
      <!-- loop for items in each row, that references 0..5, then 6..11 etc -->
      {#each Array(6) as _, i}
         {#if data[item * 6 + i]}
           <ItemCard product={data[item * 6 + i]}/>
         {/if}
      {/each}
   </div>
</VirtualList>

<script>
   import VirtualList from '@sveltejs/svelte-virtual-list'
   import ItemCard from '../components/ItemCard.svelte'

   // Array of data to display in virtual list
   export let data
   
   // New array that contains numbers 1..n
   // Dividing the data array length by 6 as there are 6 items per row
   let items = [...Array(Math.ceil(data.length / 6)).keys()]
</script>

<style lang="scss">
   .row {
      display: grid;
      gap: 1rem;
      /* change the number in the repeat to control items per line */
      grid-template-columns: repeat(3, minmax(0, 1fr));
   }
</style>

mattpilott avatar Aug 23 '21 12:08 mattpilott