Menu Close

Developing Vue Apps with the Quasar Library — Masonry Grid

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.

Masonry Grid

We can render Quasar’s q-table component as a masonry grid.

For instance, we can write:

<!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>
    <style>
      .grid-masonry {
        flex-direction: column;
        height: 700px;
      }
      .grid-masonry--2 > div:nth-child(2n + 1) {
        order: 1;
      }
      .grid-masonry--2 > div:nth-child(2n) {
        order: 2;
      }
      .grid-masonry--2:before {
        content: "";
        flex: 1 0 100% !important;
        width: 0 !important;
        order: 1;
      }
      .grid-masonry--3 > div:nth-child(3n + 1) {
        order: 1;
      }
      .grid-masonry--3 > div:nth-child(3n + 2) {
        order: 2;
      }
      .grid-masonry--3 > div:nth-child(3n) {
        order: 3;
      }
      .grid-masonry--3:before,
      .grid-masonry--3:after {
        content: "";
        flex: 1 0 100% !important;
        width: 0 !important;
        order: 2;
      }
    </style>
    <div id="q-app">
      <q-layout
        view="lHh Lpr lFf"
        container
        style="height: 100vh;"
        class="shadow-2 rounded-borders"
      >
        <div class="q-pa-md">
          <q-table
            grid
            :card-container-class="cardContainerClass"
            title="Treats"
            :data="data"
            :columns="columns"
            row-key="name"
            :filter="filter"
            hide-header
          >
            <template v-slot:item="props">
              <div class="q-pa-xs col-xs-12 col-sm-6 col-md-4">
                <q-card>
                  <q-card-section class="text-center">
                    Calories for
                    <br />
                    <strong>{{ props.row.name }}</strong>
                  </q-card-section>
                  <q-separator></q-separator>
                  <q-card-section
                    class="flex flex-center"
                    :style="{ fontSize: `${props.row.calories /5}px` }"
                  >
                    <div>{{ props.row.calories }} g</div>
                  </q-card-section>
                </q-card>
              </div>
            </template>
          </q-table>
        </div>
      </q-layout>
    </div>
    <script>
      const columns = [
        {
          name: "name",
          required: true,
          label: "Dessert",
          align: "left",
          field: (row) => row.name,
          format: (val) => `${val}`,
          sortable: true
        },
        {
          name: "calories",
          align: "center",
          label: "Calories",
          field: "calories",
          sortable: true
        },
        { name: "fat", label: "Fat (g)", field: "fat", sortable: true },
        {
          name: "calcium",
          label: "Calcium (%)",
          field: "calcium",
          sortable: true,
          sort: (a, b) => parseInt(a, 10) - parseInt(b, 10)
        }
      ];

      const data = [
        {
          name: "Frozen Yogurt",
          calories: 159,
          fat: 6.0,
          calcium: "14%"
        },
        {
          name: "Ice cream sandwich",
          calories: 237,
          fat: 9.0,
          calcium: "8%"
        },
        {
          name: "Eclair",
          calories: 262,
          fat: 16.0,
          calcium: "6%"
        },
        {
          name: "Honeycomb",
          calories: 408,
          fat: 3.2,
          calcium: "0%"
        },
        {
          name: "Donut",
          calories: 452,
          fat: 25.0,
          calcium: "2%"
        },
        {
          name: "KitKat",
          calories: 518,
          fat: 26.0,
          calcium: "12%"
        }
      ];

      new Vue({
        el: "#q-app",
        computed: {
          cardContainerClass() {
            if (this.$q.screen.gt.xs) {
              return (
                "grid-masonry grid-masonry--" +
                (this.$q.screen.gt.sm ? "3" : "2")
              );
            }

            return undefined;
          }
        },
        data: {
          columns,
          data,
          filter: ""
        }
      });
    </script>
  </body>
</html>

We populate the item prop with the masonry grid data.

In the style tag, we set the order of the flex grids to rearrange the grid in the specified order.

We arrange by size so that we form the masonry grid.

Then we add the cardContainerClass computed property to set the class of the card according to the screen’s size.

Conclusion

We can create a masonry grid with Quasar’s q-table component in our Vue app.

Posted in vue