Fading Coder

One Final Commit for the Last Sprint

Home > Tech > Content

Synchronized Main Gallery and Thumbnail Navigation with vue-awesome-swiper 3

Tech May 9 3

Installation

npm install vue-awesome-swiper@3 --save-dev

Specifying the version during installation prevents compatibility issues that comonly occur with the latest releases.

Global Setup

Register the component and styles in your entry file:

import Vue from 'vue'
import VueAwesomeSwiper from 'vue-awesome-swiper'
import 'swiper/dist/css/swiper.css'

Vue.use(VueAwesomeSwiper)

Component Template

<template>
  <div class="gallery-container">
    <!-- Main display area -->
    <swiper ref="mainSwiper" :options="mainOptions" class="main-gallery">
      <swiper-slide 
        v-for="(image, idx) in galleryImages" 
        :key="idx">
        <div class="swiper-zoom-container">
          <div class="image-container">
            <img :src="image.src" class="gallery-img">
          </div>
          <span class="image-label">{{ image.label }}</span>
        </div>
      </swiper-slide>
      <div slot="pagination" class="swiper-pagination"></div>
      <div slot="button-prev" class="swiper-button-prev"></div>
      <div slot="button-next" class="swiper-button-next"></div>
    </swiper>

    <!-- Thumbnail strip -->
    <swiper ref="thumbSwiper" :options="thumbOptions" class="thumb-gallery">
      <swiper-slide 
        v-for="(image, idx) in galleryImages" 
        :key="idx">
        <div class="swiper-zoom-container">
          <div class="thumb-container">
            <img :src="image.src" class="gallery-img">
          </div>
          <span class="image-label">{{ image.label }}</span>
        </div>
      </swiper-slide>
    </swiper>
  </div>
</template>

Styling

<style lang="scss" scoped>
.gallery-container {
  width: 100%;
  max-width: 1200px;
  margin: 0 auto;
}

.main-gallery {
  height: 420px;
  background-color: #15243B;
  
  .swiper-slide {
    display: flex;
    justify-content: center;
    align-items: center;
  }
  
  .swiper-zoom-container {
    display: flex;
    flex-direction: column;
    align-items: center;
  }
  
  .image-container {
    width: 720px;
    height: 380px;
    
    .gallery-img {
      width: 100%;
      height: 100%;
      object-fit: contain;
    }
  }
  
  .image-label {
    font-size: 16px;
    color: #ffffff;
    margin-top: 8px;
  }
}

.thumb-gallery {
  height: 160px;
  margin-top: 16px;
  border: 1px solid #3F587A;
  background-color: #15243B;
  
  .swiper-slide {
    display: flex;
    justify-content: center;
    align-items: center;
  }
  
  .thumb-container {
    width: 260px;
    height: 120px;
    margin-top: 8px;
    
    .gallery-img {
      width: 100%;
      height: 100%;
      object-fit: contain;
    }
  }
  
  .image-label {
    font-size: 14px;
    color: #ffffff;
    margin-top: 4px;
  }
  
  .swiper-slide-active {
    .gallery-img {
      border: 3px solid #3CD4FD;
    }
  }
}
</style>

Script Logic

<script>
export default {
  data() {
    return {
      galleryImages: [
        { id: 0, src: 'https://img1.baidu.com/it/u=262666228,1686642610&fm=26&fmt=auto', label: 'Waste Material' },
        { id: 1, src: 'https://img0.baidu.com/it/u=1416201738,4279486216&fm=26&fmt=auto', label: 'Waste Material' },
        { id: 2, src: 'https://img0.baidu.com/it/u=2378821321,544368891&fm=26&fmt=auto', label: 'Waste Material' },
        { id: 3, src: 'https://img2.baidu.com/it/u=1118985261,4234949595&fm=26&fmt=auto', label: 'Waste Material' },
        { id: 4, src: 'https://img1.baidu.com/it/u=3151984749,173677495&fm=26&fmt=auto', label: 'Waste Material' },
        { id: 5, src: 'https://img2.baidu.com/it/u=3704585441,2694001779&fm=26&fmt=auto', label: 'Waste Material' }
      ],
      mainOptions: {
        navigation: {
          nextEl: '.swiper-button-next',
          prevEl: '.swiper-button-prev'
        },
        observer: true,
        observeParents: true,
        grabCursor: true
      },
      thumbOptions: {
        slidesPerView: 3,
        spaceBetween: 30,
        direction: 'horizontal',
        centeredSlides: true,
        grabCursor: true,
        slideToClickedSlide: true,
        watchSlidesVisibility: true
      }
    }
  },
  updated() {
    this.$nextTick(() => {
      const mainInstance = this.$refs.mainSwiper.swiper
      const thumbInstance = this.$refs.thumbSwiper.swiper
      
      mainInstance.controller.control = thumbInstance
      thumbInstance.controller.control = mainInstance
    })
  }
}
</script>

Implementation Notes

Why updated Lifecycle Hook

Accessing $refs in the mounted hook returns undefined because the Swiper instance hasn't been initialized yet. The updated hook fires whenever the component re-renders, ensuring the Swiper DOM elements exist. How ever, for more reliable initialization, considre using a custom method called from a child component or with a small delay.

Accessing Swiper Instances

In vue-awesome-swiper@3, access the Swiper instance via this.$refs.mainSwiper.swiper. The newer version 4 uses this.$refs.mainSwiper.$swiper, but version 3 does not use the nested $refs structure. Verify this by logging this.$refs.mainSwiper to see its actual properties.

Two-Way Synchronization

Setting control properties on both Swiper instances establishes bidirectional communication. Clicking thumbnails updates the main gallery, and navigating the main gallery updates the thumbnail position. The slideToClickedSlide: true option ensures the thumbnail strip auto-scrolls to show the active slide.

Related Articles

Understanding Strong and Weak References in Java

Strong References Strong reference are the most prevalent type of object referencing in Java. When an object has a strong reference pointing to it, the garbage collector will not reclaim its memory. F...

Comprehensive Guide to SSTI Explained with Payload Bypass Techniques

Introduction Server-Side Template Injection (SSTI) is a vulnerability in web applications where user input is improper handled within the template engine and executed on the server. This exploit can r...

Implement Image Upload Functionality for Django Integrated TinyMCE Editor

Django’s Admin panel is highly user-friendly, and pairing it with TinyMCE, an effective rich text editor, simplifies content management significantly. Combining the two is particular useful for bloggi...

Leave a Comment

Anonymous

◎Feel free to join the discussion and share your thoughts.