Today I’ll show you how I used vuetify‘s carousel element to get a result requested by a client. The requirements are defined as follows:
- images are grouped so that on desktop there are 4 visible at once, on tablet 3 visible at once and on mobile 2 visible at once
- when the user goes to the next slide all previously visible items are swiped away and new images are shown
- the number of images is not known in advance
Working demo for those, who want to see it first.
Introduction
Vue.js is a javascript framework, that is a base for the vuetify – material design framework. I rarely use frameworks in my personal projects, so when I have to use them in a client’s project it’s a learning process for me and I like to document it for the future reference, just in case I’ll need to do the same thing again. That’s the introduction, now the code.
Template
Template is the part of a vue component, that is responsible for displaying the data. It can use usual HTML tags (like div
or img
), vue components (when using vuetify these are for example v-carousel
or v-carousel-item
) and the magic template
tag, that does not have a representation in generated HTML code.
Ready template looks like this:
<v-carousel>
<template v-for="(item, index) in slider">
<v-carousel-item
v-if="(index + 1) % columns === 1 || columns === 1"
:key="index"
>
<v-row class="flex-nowrap">
<template v-for="(n,i) in columns">
<template v-if="(+index + i) < slider.length">
<v-col :key="i">
<!-- the content -->
{{ +index + i + 1}}
</v-col>
</template>
</template>
</v-row>
</v-carousel-item>
</template>
</v-carousel>
It looks quite complicated, so let’s break it down.
<v-carousel>
We want to use the v-carousel
component as the base. I did not specify any attributes, but there are quite a few. They do not influence the final effect, so feel free to use them for customisation.
<template v-for="(item, index) in slider">
We want to display all elements from slider
array. These can be simple strings of text, images, advanced objects, anything. To make the widget work, we do not need the item’s interns, but its index
in the slider
array. Because we want to execute some more logic before displaying anything (specifically: use v-if
) we use the template
element. If you want to learn more about it have a look at Vue’s documentation.
<v-carousel-item
v-if="(index + 1) % columns === 1 || columns === 1"
:key="index"
>
The simple part: we want to use v-carousel-item
component to display a single slide – a container for the multiple elements to be shown at once. The more complicated part goes this way:
We have the number of elements we want to display at once in the columns
variable – it may be 1
, 2
, 3
, 4
and so on; an integer. If it is set to 1
we want to display every element inside its own v-carousel-item
. If we want more elements in one slide, we need to check for that comparing the current item’s index
with the number of element per slide (columns
). If we want 3 elements per slide, we trigger the generation of new slide for the first, fourth, seventh and so on items. They share the property of leaving the remainder of 1 when divided by 3.
The last thing we do here is setting the :key
to make sure the items get rendered properly. If you want to know more about it have a look at Vue’s documentation.
<v-row class="flex-nowrap">
Inside an item we want a row to keep our elements aligned properly. We also set the flex-nowrap
property to prevent wrapping of the slide’s contents.
<template v-for="(n,i) in columns">
Now we want to display exactly as many items as indicated by columns
property. Assuming columns
is equal to 3
, this translates into for (let i = 0; i < 3; i++)
.
<template v-if="(+index + i) < slider.length">
Now that we initialized new slide we need to check if it can be filled by remaining items, because in case we want to display 4 items and have only 3 left we need to react accordingly. I have chosen to let the remaining elements stretch and take the whole width, but another strategy would be to generate all the slots always and only check if we still have items while writing into those slots.
<v-col :key="i">
Another wrapper to make the elements inside the slide take equal width. Whatever we write inside it is the actual content.
Logic
Now with our template ready to go we need to add the logic to keep the columns
in sync with the current viewport. This gets done with a computed property.
computed: {
columns() {
if (this.$vuetify.breakpoint.xl) {
return 4;
}
if (this.$vuetify.breakpoint.lg) {
return 3;
}
if (this.$vuetify.breakpoint.md) {
return 2;
}
return 1;
}
},
We go from the biggest screen size to the smallest and whenever we get a match we return the number of columns to generate. If we haven’t found a match, we return the default – number of columns for the smallest screen size. The breakpoints are defined by vuetify and can be looked up in vuetify’s documentation.
And that’s it when it comes to custom things. If you are interested in the whole code needed to render a vuetify carousel with multiple items per slide checkout this demo.
Conclusion
Even if I’m not an everyday framework user getting started and achieving my goals with vue and vuetify was rather pleasant. Both frameworks have good documentation and lot’s to offer. Building something, that does not require a lot of maths, was a good experience, however if I needed to respond to more edge cases or got into problems with performance I would rather go with vanilla javascript.