intersection-scroller-vue

1.0.2 • Public • Published

intersection-scroller-vue

Infinite scrolling implemented with intersection observer instead of scroll events. "The Intersection Observer API provides a way to asynchronously observe changes in the intersection of a target element with an ancestor element or with a top-level document's viewport." You can read more about Intersection Observer on the following link -> (https://developer.mozilla.org/en-US/docs/Web/API/Intersection_Observer_API)

This package aims to enable loading paginated data, displaying it in a grid based layout, only filling your elements with data that are onscreen.

Features:

  • Works in Chrome
  • Works in Firefox
  • Works in Microsoft Edge
  • Works in IE
  • It might work in other browsers too, but testing is WIP for other browsers
  • Automatically load more data when the user scrolls to the bottom, or manually clicks on the arrow if intersection observer is not supported
  • You can add your custom component in the template slot be it simple divs, cards, etc.
  • Only elements onscreen is filled with data, your offscreen elements will be empty. When offscreen elements come into the viewport they will be filled with data automatically.

In case intersection observer is not supported on the current platform, some features won't work

Install

$ npm install intersection-scroller-vue

Usage

Properties:

  • list: [ARRAY] [REQUIRED] This property is your array where your data is
  • itemsCount: [NUMBER] [REQUIRED] the max count of the data
  • itemWidth: [NUMBER] [REQUIRED] the width of each individual element in the scoped slot.
  • itemsGap: [NUMBER] [NOT REQUIRED] [DEF: 0]: the horizontal space between your elements if they have any. el / row is calculated based on this too, so it's important to set it.
  • itemsPerPage: [NUMBER] [REQUIRED] How many items you load / page. Should be divisible with items / row without remainder.
  • listChanged: [BOOLEAN] [REQUIRED] Boolean property which should be false first, and when your data changes you have to set it true
  • indexBy: [STRING] [NOT REQUIRED] [DEF: id] name of the property in your list to find index by, should be unique.
  • containerClass: [STRING] [NOT REQUIRED] [DEF: ""] classes the scrollContainer div should have,
  • iconContainerClass: [STRING] [NOT REQUIRED] [DEF: ""] classes the container below your scrollingContainer should have
  • loadingIconClass: [STRING] [NOT REQUIRED] [DEF: ""] classes for the loading icon, will show up when items are loading, if left empty, no icon will show up
  • loadMoreClass: [STRING] [NOT REQUIRED] [DEF: ""] classes for the load more icon, will show up at the end of the list if for some reason intersection observer is not working, clicking on it loads more data. if left empty, no icon will show up.
  • noMoreMessage: [STRING] [NOT REQUIRED] [DEF: null] the message to be shown at the end of the list when there is no more data.

Events

  • @itemsFn: In this event you have to provide the function of getting more data from the server, or any other place. This is the place where you have to do any modifications to the returned data (ex.: make a vuex store commit, map values to new ones etc.) and add your data to the array you specified in the list property be it in the component, or vuex, or anywhere accessible. Also, don't forget to set your listChanged property to true at the end of the function. itemsPerRow is emitted with this event, you can recalculate itemsPerPage with this.
  • @updated: Set your listChanged boolean property to false here

Template slot:

The infinite scroller component returns each individual item in slot-scope You have to provide :key as index and :id as item-${index} If you want your data to be filled only for onscreen items wrap it in a div and check for visiblity

    <template slot-scope="{ item, index }">
        <q-card
          :style="`width:${itemWidth}px; height:500px;`"
          class="q-ma-sm"
          :key="index"
          :id="`item-${index}`"
        >
          <div v-if="item.isVisible">
            <p class="text-center">{{ item.label }}</p>
            <q-img basic width="300px" :src="item.imgSrc" alt="macskás kép" />
          </div>
        </q-card>
      </template> 

Usage example

   <intersection-scroller
      :list="bigList"
      :itemsCount="maxLength"
      :itemWidth="itemWidth"
      :itemsPerPage="pageCount"
      :items-gap="itemsGap"
      :listChanged="listChanged"
      indexBy="label"
      containerClass="row justify-center"
      iconContainerClass="row justify-center q-mt-lg"
      loadingIconClass="fas fa-spinner fa-2x fa-pulse"
      loadMoreClass="fas fa-chevron-down fa-2x bounce"
      :noMoreMessage="noMoreMsg"
      @itemsFn="getItems($event)"
      @updated="listChanged = false"
    >
      <template slot-scope="{ item, index }">
        <q-card
          :style="`width:${itemWidth}px; height:500px;`"
          class="q-ml-sm q-mt-sm"
          :key="index"
          :id="`item-${index}`"
        >
          <div v-if="item.isVisible">
            <p class="text-center">{{ item.label }}</p>
            <q-img basic width="300px" :src="item.imgSrc" alt="macskás kép" />
          </div>
        </q-card>
      </template>
    </intersection-scroller>
<script>
import IntersectionScroller from "intersection-scroller-vue";
export default {
  components: {
    IntersectionScroller
  },
  data() {
    return {
      bigList: [],
      maxLength: 120,
      itemWidth: 300,
      itemOffset: 100,
      pageCount: 12,
      noMoreMsg: "No more items...",
      listChanged: false,
      itemsGap: 8
    };
  },
  methods: {
    getCatImg() {
      const randomNum = () => {
        return Math.floor(Math.random() * 100000);
      };
      const url = "https://source.unsplash.com/collection/139386/100x100/?sig=";
      return url + randomNum();
    },
    async getItems(itemsPerRow) {
      const length = this.bigList.length;
      this.pageCount = this.getPageCount(itemsPerRow);
      this.maxLength = this.pageCount * 10;
      for (let i = 0; i < this.pageCount; i++) {
        this.bigList.push({
          label: `CARD ${+ length}`,
          isVisible: true,
          imgSrc: this.getCatImg()
        });
      }
      this.listChanged = true;
    },
    getPageCount(itemsPerRow) {
      return itemsPerRow < 5 ? 12 : itemsPerRow === 5 ? 15 : itemsPerRow * 2;
    }
  }
};
</script>

Demo

Check out the demo on the following link -> https://intersectionscroller.now.sh (images might not load properly due to external source)

Package Sidebar

Install

npm i intersection-scroller-vue

Weekly Downloads

0

Version

1.0.2

License

none

Unpacked Size

13.4 kB

Total Files

4

Last publish

Collaborators

  • gyulavaripeter