How do I lazy load item lists on Vuejs and Vuetify's lazyload?

Viewed 13352

Im trying to make an infinite scroll list but it's really not lazy loading, been stuck with this for hours, the whole list will come in.

      .....
    <v-col
      v-for="(post, i) in posts"
      :key="i"
      cols="12"
    >
    <v-lazy
    v-model="isActive"
    :options="{
      threshold: .5
    }"
    transition="fade-transition"
  >
          {{Content here}}
     </....

API used for test : https://jsonplaceholder.typicode.com/posts

2 Answers

There is a new virtual-scroller component, but it doesn't work with responsive content like grid rows/cols. Instead use v-lazy...

I discovered that the columns need to have defined min-height (approx. to the expected height of the cards) in order for the v-lazy intersection observer to work. Use something like a v-sheet or v-responsive to set the min-height and contain the cards.

Also bind the v-model of the v-lazy to each post (ie: post.isActive), instead of a global isActive var...

        <v-col lg="3" md="4" sm="6" cols="12" v-for="(post, index) in posts">
                <v-sheet min-height="250" class="fill-height" color="transparent">
                    <v-lazy 
                        v-model="post.isActive" :options="{
                            threshold: .5
                        }"
                        class="fill-height">
                        <v-card class="fill-height" hover>
                            <v-card-text>
                                <v-row :key="index" @click="">
                                    <v-col sm="10" cols="12" class="text-sm-left text-center">
                                        #{{ (index+1) }}
                                        <h2 v-html="post.title"></h2>
                                        <div v-html="post.body"></div>
                                    </v-col>
                                </v-row>
                            </v-card-text>
                        </v-card>
                    </v-lazy>
                </v-sheet>
        </v-col>

   

Demo: https://codeply.com/p/eOZKk873AJ

I can suggest another solution with v-intersect, which works perfect for me.

Sorry, the snippet may be not working as composed of my code, but the idea should be pretty clear

<template>
  <v-list class="overflow-y-auto" max-height="500">
    <v-list-item v-for="item in items">
      {{ item.name }}
    </v-list-item>
    <v-skeleton-loader v-if="moreDataToAvailable" v-intersect="loadNextPage" type="list-item@5" />
  </v-list>
</template>

<script lang="ts">
import Vue from 'vue'

const pageSize = 10

export default Vue.extend({
  data(): any {
    return {
      pageLoaded: 0,
      totalCount: 100,//fetch from API
      items: []
    }
  },
  computed: {
    moreDataToAvailable (): boolean {
      return Math.ceil(this.totalCount / pageSize) - 1 > this.pageLoaded
    }
  },
  methods {
    async loadNextPage (entries: IntersectionObserverEntry[]) {
      if (entries[0].isIntersecting && this.moreDataToAvailable) {
        const nextPage = this.pageLoaded + 1
        const loaded = await this.loadPage(nextPage) //API call
        loaded.data.forEach((item: any) => this.items.push(item))
        this.totalCount = loaded.totalCount
        this.pageLoaded = nextPage
      }
    },
  }
})
</script>
Related