DEV Community πŸ‘©β€πŸ’»πŸ‘¨β€πŸ’»

DEV Community πŸ‘©β€πŸ’»πŸ‘¨β€πŸ’» is a community of 968,873 amazing developers

We're a place where coders share, stay up-to-date and grow their careers.

Create account Log in
Cover image for Building an image carousel with Vue.js
tsanak
tsanak

Posted on

Building an image carousel with Vue.js

In my few years of experience as a web developer I have used more than a dozen carousel plugins, some of them were really good and some of them were rather clunky.

Recently I wanted to use a small image carousel(for a personal project of mine) that would cover the upper part of a card. The carousel should have arrows and thumbnails to navigate through the images and the thumbnails should be on the bottom of the carousel.

I was tempted to use something like owl-carousel and get on with my day, but I also kind of wanted to build something new with Vue, which I have been learning for a few months now.

Since I had plenty of time I fired up my favorite IDE and started a new project.

For this project I used Bulma (a CSS framework based on Flexbox) and of course Vue.js. If you are new to Vue I encourage you to read my first post and the awesome documentation.

Sneak peek

alt text

Let’s get technical

HTML skeleton of the project

<section class="section" id="app">
    <div class="columns">
        <div class="column is-4">
            <div class="card">
                <div class="card-content">
                    <div class="card-carousel">
                        <div class="card-img">
                            <img src="/some-image.jpg" alt="Some image">
                            <div class="actions">
                                <span class="prev">
                                    <i class="fas fa-chevron-left"></i>
                                </span>
                                <span class="next">
                                    <i class="fas fa-chevron-right"></i>
                                </span>
                            </div>
                        </div>
                        <div class="thumbnails">
                            <div class="thumbnail-img">
                                <img src="/some-thumbnail.jpg" alt="Some thumbnail">
                            </div>
                            <div class="thumbnail-img active">
                                <img src="/some-thumbnail.jpg" alt="Some thumbnail">
                            </div>
                            <div class="thumbnail-img">
                                <img src="/some-thumbnail.jpg" alt="Some thumbnail">
                            </div>
                        </div>
                    </div>
                    <p>Card description.</p>
                </div>
            </div>
        </div>
    </div>
</section>
Enter fullscreen mode Exit fullscreen mode

After a little CSS it ended up looking like this:
alt text

Now that we got the styling out of the way, we can focus on the functionality πŸ€–

<div class="card-carousel">
    <div class="card-img">
        <img :src="currentImage" alt="">
        <div class="actions">
            <span @click="prevImage" class="prev">
                <i class="fas fa-chevron-left"></i>
            </span>
            <span @click="nextImage" class="next">
                <i class="fas fa-chevron-right"></i>
            </span>
        </div>
    </div>
    <div class="thumbnails">
        <div 
            v-for="(image, index) in  images"
            :key="image.id"
            :class="['thumbnail-image', (activeImage == index) ? 'active' : '']"
            @click="activateImage(index)"
        >
            <img :src="image.thumb">
        </div>
    </div>
</div>
Enter fullscreen mode Exit fullscreen mode

A short explanation

<!-- 
    Bind the source of the image to a variable,
    so when the variable changes, so does the photo
-->
<img :src="currentImage" alt="">
<!-- 
    Loop through the images array,
    @click="activateImage(index)" on click call the function activateImage 
    :class="['thumbnail-image', (activeImage == index) ? 'active' : '']"
    bind the class of the div to an array. Always show 'thumbnail-image' class 
    and show the class 'active' only for the image that is currently active
-->
<div 
    v-for="(image, index) in  images"
    :key="image.id"
    :class="['thumbnail-image', (activeImage == index) ? 'active' : '']"
    @click="activateImage(index)"
>
    <img :src="image.thumb">
</div>
Enter fullscreen mode Exit fullscreen mode

and all the JS code that was needed:

    var app = new Vue({
        el: '#app',
        data() {
            return {
                //Array to hold all carousel images
                images: [
                    {
                        id: '1',
                        big: 'images/p1.jpeg',
                        thumb: 'images/thumbs/p1.jpeg'
                    },
                    {
                        id: '2',
                        big: 'images/p2.jpeg',
                        thumb: 'images/thumbs/p2.jpeg'
                    },
                    {
                        id: '3',
                        big: 'images/p3.jpeg',
                        thumb: 'images/thumbs/p3.jpeg'
                    },
                    {
                        id: '4',
                        big: 'images/p4.jpeg',
                        thumb: 'images/thumbs/p4.jpeg'
                    }
                ],
                //Index of the active image on the images array
                activeImage: 0
            }
        },
        computed: {
            // currentImage gets called whenever activeImage changes
            // and is the reason why we don't have to worry about the 
            // big image getting updated
            currentImage() {
                return this.images[this.activeImage].big;
            }
        },
        methods: {
            // Go forward on the images array 
            // or go at the first image if you can't go forward :/ 
            nextImage() {
                var active = this.activeImage + 1;
                if(active >= this.images.length) {
                    active = 0;
                }
                this.activateImage(active);
            },
            // Go backwards on the images array 
            // or go at the last image
            prevImage() {
                var active = this.activeImage - 1;
                if(active < 0) {
                    active = this.images.length - 1;
                }
                this.activateImage(active);
            },
            activateImage(imageIndex) {
                this.activeImage = imageIndex;
            }
        }
    });
Enter fullscreen mode Exit fullscreen mode

Here is the finished project (again πŸ˜…)
alt text

πŸŽ‰Thank you for reading through all this and I hope you found something helpfulπŸŽ‰

You can find all the code on github

All the photos were taken from Pexels.com
https://www.pexels.com/photo/bang-blast-celebration-color-287487/
https://www.pexels.com/photo/person-hands-squash-fruit-112352/
https://www.pexels.com/photo/action-blur-car-daylight-246320/
https://www.pexels.com/photo/auto-automobile-blur-bokeh-242276/

Top comments (9)

Collapse
 
lauragift21 profile image
Gift Egwuenu

This is really cool. Great Job.

Collapse
 
tsanak profile image
tsanak Author

Thank you. Let me know if you are interested in some more advanced Vue posts.

Collapse
 
lauragift21 profile image
Gift Egwuenu

Yeah sure. I will really love to see those.

Collapse
 
dougblackjr profile image
Doug Black

Well done!

Collapse
 
tsanak profile image
tsanak Author

Thanks a lot!

Collapse
 
batyr71 profile image
Batyr Paşşy

Thank you for sharing. Please make mo tuts in this style. Simple and without CLI

Collapse
 
tsanak profile image
tsanak Author

Thank you for your comment. I have some tutorials in my mind, will write them when I have some free time.

Collapse
 
nagwan profile image
nagwan sami

awesome, thanks 🌸

Collapse
 
turajek profile image
Turajek

Well done! This is so much helpful! Thank you!

This post blew up on DEV in 2020:

js visualized

πŸš€βš™οΈ JavaScript Visualized: the JavaScript Engine

As JavaScript devs, we usually don't have to deal with compilers ourselves. However, it's definitely good to know the basics of the JavaScript engine and see how it handles our human-friendly JS code, and turns it into something machines understand! πŸ₯³

Happy coding!