Categories
Quasar

Developing Vue Apps with the Quasar Library — Virtual Scrolling

Spread the love

Quasar is a popular Vue UI library for developing good looking Vue apps.

In this article, we’ll take a look at how to create Vue apps with the Quasar UI library.

Horizontal Virtual Scrolling

We can add the virtual-scroll-horizontal prop to make the virtual scrolling container horizontal:

<!DOCTYPE html>
<html>
  <head>
    <link
      href="https://fonts.googleapis.com/css?family=Roboto:100,300,400,500,700,900|Material+Icons"
      rel="stylesheet"
      type="text/css"
    />
    <link
      href="https://cdn.jsdelivr.net/npm/quasar@1.12.13/dist/quasar.min.css"
      rel="stylesheet"
      type="text/css"
    />
  </head>
  <body class="body--dark">
    <script src="https://cdn.jsdelivr.net/npm/vue@^2.0.0/dist/vue.min.js"></script>
    <script src="https://cdn.jsdelivr.net/npm/quasar@1.12.13/dist/quasar.umd.min.js"></script>
    <div id="q-app">
      <q-virtual-scroll
        style="max-height: 300px;"
        :items="heavyList"
        separator
        virtual-scroll-horizontal
      >
        <template v-slot="{ item, index }">
          <q-item :key="index" dense>
            <q-item-section>
              <q-item-label>
                #{{ index }} - {{ item.label }}
              </q-item-label>
            </q-item-section>
          </q-item>
        </template>
      </q-virtual-scroll>
    </div>
    <script>
      const maxSize = 10000;
      const heavyList = [];

      for (let i = 0; i < maxSize; i++) {
        heavyList.push({
          label: `option ${i}`
        });
      }

      new Vue({
        el: "#q-app",
        data: {
          heavyList
        }
      });
    </script>
  </body>
</html>

Customized Item Template

We can customize the item template to display items the way we want:

<!DOCTYPE html>
<html>
  <head>
    <link
      href="https://fonts.googleapis.com/css?family=Roboto:100,300,400,500,700,900|Material+Icons"
      rel="stylesheet"
      type="text/css"
    />
    <link
      href="https://cdn.jsdelivr.net/npm/quasar@1.12.13/dist/quasar.min.css"
      rel="stylesheet"
      type="text/css"
    />
  </head>
  <body class="body--dark">
    <script src="https://cdn.jsdelivr.net/npm/vue@^2.0.0/dist/vue.min.js"></script>
    <script src="https://cdn.jsdelivr.net/npm/quasar@1.12.13/dist/quasar.umd.min.js"></script>
    <div id="q-app">
      <q-virtual-scroll style="max-height: 300px;" :items="heavyList" separator>
        <template v-slot="{ item, index }">
          <q-banner
            v-if="item.banner === true"
            class="bg-black text-white q-py-xl"
            :key="index"
          >
            #{{ index }} - {{ item.label }}
          </q-banner>

          <q-item v-else :key="index" dense clickable>
            <q-item-section>
              <q-item-label>
                #{{ index }} - {{ item.label }}
              </q-item-label>
            </q-item-section>
          </q-item>
        </template>
      </q-virtual-scroll>
    </div>
    <script>
      const maxSize = 10000;
      const heavyList = [];

      for (let i = 0; i < maxSize; i++) {
        heavyList.push({
          label: `option ${i}`,
          banner: i === 0
        });
      }

      new Vue({
        el: "#q-app",
        data: {
          heavyList
        }
      });
    </script>
  </body>
</html>

We just put the item template in the default slot.

Table Style Virtual Scrolling Container

Also, we can display the items in a table style virtual scrolling container:

<!DOCTYPE html>
<html>
  <head>
    <link
      href="https://fonts.googleapis.com/css?family=Roboto:100,300,400,500,700,900|Material+Icons"
      rel="stylesheet"
      type="text/css"
    />
    <link
      href="https://cdn.jsdelivr.net/npm/quasar@1.12.13/dist/quasar.min.css"
      rel="stylesheet"
      type="text/css"
    />
  </head>
  <body class="body--dark">
    <script src="https://cdn.jsdelivr.net/npm/vue@^2.0.0/dist/vue.min.js"></script>
    <script src="https://cdn.jsdelivr.net/npm/quasar@1.12.13/dist/quasar.umd.min.js"></script>
    <div id="q-app">
      <q-virtual-scroll
        type="table"
        style="max-height: 70vh;"
        :virtual-scroll-item-size="48"
        :virtual-scroll-sticky-size-start="48"
        :virtual-scroll-sticky-size-end="32"
        :items="heavyList"
      >
        <template v-slot="{ item: row, index }">
          <tr :key="index">
            <td>#{{ index }}</td>
            <td v-for="col in columns" :key="index + '-' + col">
              {{ row[col] }}
            </td>
          </tr>
        </template>
      </q-virtual-scroll>
    </div>
    <script>
      const data = [
        {
          name: "Frozen Yogurt",
          calories: 159,
          fat: 6.0,
          carbs: 24
        },
        {
          name: "Ice cream sandwich",
          calories: 237,
          fat: 9.0,
          carbs: 37
        },
        {
          name: "Eclair",
          calories: 262,
          fat: 16.0,
          carbs: 23
        },
        {
          name: "Cupcake",
          calories: 305,
          fat: 3.7,
          carbs: 67
        },
        {
          name: "Gingerbread",
          calories: 356,
          fat: 16.0,
          carbs: 49
        },
        {
          name: "Jelly bean",
          calories: 375,
          fat: 0.0,
          carbs: 94
        },
        {
          name: "Lollipop",
          calories: 392,
          fat: 0.2,
          carbs: 98
        },
        {
          name: "Honeycomb",
          calories: 408,
          fat: 3.2,
          carbs: 87
        },
        {
          name: "Donut",
          calories: 452,
          fat: 25.0,
          carbs: 51
        },
        {
          name: "KitKat",
          calories: 518,
          fat: 26.0,
          carbs: 65
        }
      ];

      const columns = ["name", "calories", "fat", "carbs"];

      const heavyList = [];
      for (let i = 0; i <= 1000; i++) {
        heavyList.push(...data);
      }
      Object.freeze(heavyList);
      Object.freeze(columns);

      new Vue({
        el: "#q-app",
        data: {
          columns,
          heavyList
        }
      });
    </script>
  </body>
</html>

We render the columns in the default slot.

And we set the virtual-scroll-item-size prop to change height or width of the item in pixels, depending on if the list is vertical or horizontal respectively

The virtual-scroll-sticky-size-start prop to change the height or width of the sticky part in pixels, depending on if the list is vertical or horizontal respectively.

And the virtual-scroll-sticky-size-end prop to change the height or width of the bottom sticky part in pixels, depending on if the list is vertical or horizontal respectively.

Conclusion

We can add a virtual scrolling container with various styles with Quasar’s q-virtual-scroll component.

By John Au-Yeung

Web developer specializing in React, Vue, and front end development.

Leave a Reply

Your email address will not be published. Required fields are marked *