Implementing an Infinite Scroll with Vue.js

Dave Berning

Infinite scrolls have their place on the web, but it aren’t for every website or application. They’re especially useful when you need to load large amounts of data or images when the user needs them rather than at all once. Social media outlets like Twitter, Facebook, and Instagram have popularized this over the years. Integrating your own infinite scroll on your website or application is easier than you might think.

This article is going to be using the Random User API. The API describes itself as “Like Lorem Ipsum, but for people”. It’s not only great for this implementation, but it’s also very useful for mocking up user profiles for future projects.

Before you start, create a new Vue.js project using the Vue CLI webpack-simple template. This example will be using Axios and MomentJS for data fetching and date formatting, respectively.

$ vue init webpack-simple infinite-scroll-vuejs

Getting Initial User Data

There are various npm packages for infinite scroll that you can use for your Vue app, but some of these may be overkill. For this post, we’ll go without a plugin or package and we’re going to be writing a simple JavaScript function that fetches a new set of data when scrolled to the bottom of the browser window.

Before we start integrating the infinite scroll, let’s fetch and set some initial data on page load:

App.vue

data () {
  return {
    persons: []
  }
},
methods: {
  getInitialUsers () {
    for (var i = 0; i < 5; i++) {
      axios.get(`https://randomuser.me/api/`)
        .then(response => {
          this.persons.push(response.data.results[0]);
        });
    }
  }
},
beforeMount() {
  this.getInitialUsers();
}

It's worth noting that it's not recommended to make five services calls on load. The Random User API only returns one random user at a time. So in order to get five initial users, five services calls were needed.

If you console log your persons array or open up the Vue Devtools, you should see an array of five users. If so, great! Let’s iterate through this data in the template, style them up, and continue:

App.vue

<template>
  <div id="app">
    <h1>Random User</h1>
    <div class="person" v-for="person in persons">
      <div class="left">
        <img :src="person.picture.large">
      </div>
      <div class="right">
        <p>{{ person.name.first }} {{ person.name.last }}</p>
        <ul>
          <li>
            <strong>Birthday:</strong> {{ formatDate(person.dob) }}
          </li>
          <li class="text-capitalize">
            <strong>Location:</strong> {{ person.location.city }},
            {{ person.location.state }}
          </li>
        </ul>
      </div>
    </div>
  </div>
</template>

<script>
...
</script>

<style lang="scss">
 /* Optional Styles */
 .person {
    background: #ccc;
    border-radius: 2px;
    width: 20%;
    margin: 0 auto 15px auto;
    padding: 15px;

    img {
      width: 100%;
      height: auto;
      border-radius: 2px;
    }

    p:first-child {
      text-transform: capitalize;
      font-size: 2rem;
      font-weight: 900;
    }

    .text-capitalize {
      text-transform: capitalize;
    }
  }
</style>

Implementing the Infinite Scroll Logic

Now for the reason why you’re here… the infinite scroll! 🧞‍ In your component’s methods, you’ll need to create a new function called, scroll() and have that loaded in the mounted() lifecycle method.

This scroll() method should have a simple condition that calculates the bottom of the page, evaluates it as true or false, and executes something. We’ll make use of the document object’s documentElement.scrollTop, documentElement.offsetHeight properties and of window’s innerHeight properties to determine if scroll as at the bottom:

window.onscroll = () => {
  let bottomOfWindow = document.documentElement.scrollTop + window.innerHeight === document.documentElement.offsetHeight;

  if (bottomOfWindow) {
    // Do something, anything!
  }
};

Inside this condition, let’s add a GET service method with Axios to fetch another random user from the Random User API.

App.vue

methods: {
  ...,
  scroll (person) {
    window.onscroll = () => {
      let bottomOfWindow = document.documentElement.scrollTop + window.innerHeight === document.documentElement.offsetHeight;

      if (bottomOfWindow) {
        axios.get(`https://randomuser.me/api/`)
          .then(response => {
            person.push(response.data.results[0]);
          });
      }
    };
  },
},
mounted() {
  this.scroll(this.person);
}

This function makes a service call and adds a new random “user” to the persons array only when the user scrolls to the bottom of the page. At this point, you should be able to scroll… infinitely and see a new “user” each time.

Conclusion

Infinite scrolling sounds intimidating but as demonstrated, it’s quite simple. With each scroll to the bottom of the page, we fetch new data with Axios then push that data to an array. To lazy load images, just push an image source to a data array, iterate through it in your template and bind your <img :src=""> to the array.

  Tweet It

🕵 Search Results

🔎 Searching...

Sponsored by #native_company# — Learn More
#native_title# #native_desc#
#native_cta#