djangodev
djangodev

Reputation: 353

What am I doing wrong with Swiper.js in Vue 2?

As the title says, I'm trying to use swiperjs with Vue 2. I've used the API from swiper and another library "vue-awesome-swiper" to try and get it working. I get to the point with both approaches where everything appears functional but it's just the navigation buttons that aren't working and touch swiping is also disfuncitonal.

In each of the following approaches, I'm getting a seemingly perfect swiper but navigation is not working in either. I'm using vue 2.6 and swiper 6.7.

Here's what I have using vue-awesome-swiper:

<template>
  <div>
    <h2 class="swiper-container__title">{{ sliderHeading }}</h2>
    <swiper :options="swiperOption" class="swiper">
      <!-- Loops through item data and creates a carousel item -->
      <div v-for="item in mediaItems" :key="item.id">
        <swiper-slide>
          <item :mediaItem="item"></item>
        </swiper-slide>
      </div>

      <div class="swiper-button-prev" slot="button-prev"></div>
      <div class="swiper-button-next" slot="button-next"></div>
    </swiper>
    <hr class="carousel-container__separator" />
  </div>
</template>

<script>
import Item from "./Item.vue";
import { Swiper, SwiperSlide } from "vue-awesome-swiper";
import "swiper/swiper-bundle.min.css";

export default {
  name: "swiper-example-pagination-progress",
  title: "Progress pagination",
  components: {
    Item,
    Swiper,
    SwiperSlide
  },
  data() {
    return {
      swiperOption: {
        slidesPerView: 7,
        spaceBetween: 30,
        loop: true,
        navigation: {
          nextEl: ".swiper-button-next",
          prevEl: ".swiper-button-prev"
        }
      }
    };
  },
  props: {
    mediaItems: {
      type: Array,
      default: () => []
    },
    sliderHeading: String
  }
};
</script>

And here I have the same results trying to use the swiper.js API myself:

<template>
  <div class="carousel-container wow fadeIn" data-wow-duration="3s">
    <div ref="slider" class="swiper-container">
      <h2 class="swiper-container__title">{{ sliderHeading }}</h2>

      <!-- Loops through item data and creates a carousel item -->
      <div class="swiper-wrapper">
        <div v-for="item in mediaItems" :key="item.id">
          <item class="swiper-slide" :mediaItem="item"></item>
        </div>
      </div>

      <div ref="nextEl" class="swiper-button-prev"></div>
      <div ref="prevEl" class="swiper-button-next"></div>
    </div>

    <hr class="carousel-container__separator" />
  </div>
</template>

<script>
import Item from "./Item.vue";
import Swiper from "swiper";

export default {
  components: {
    Item
  },
  props: {
    mediaItems: {
      type: Array,
      default: () => []
    },
    sliderHeading: String
  },
  mounted() {
    this.slider = new Swiper(this.$refs.slider, {
      init: true,
      slidesPerView: 7,
      loop: true,
      spaceBetween: 14,
      observer: true,
      breakpoints: {
        1145: {
          slidesPerView: 5
        },
        699: {
          slidesPerView: 3
        }
      },
      navigation: {
        nextEl: this.$refs.nextEl,
        prevEl: this.$refs.prevEl
      }
    });
  },
  computed: {},
  methods: {},
  data: function() {
    return {
      slider: null
    };
  }
};
</script>

Upvotes: 1

Views: 11065

Answers (1)

tony19
tony19

Reputation: 138696

Unnecessary div wrapper

vue-aweomse-swiper expects swiper-slide to be immediate descendants, so remove the div wrapper; and move the v-for and key props to swiper-slide:

<!-- BEFORE -->
<swiper>
  <div v-for="item in mediaItems" :key="item.id">
    <swiper-slide>
      ...
    </swiper-slide>
  </div>
</swiper>
<!-- AFTER -->
<swiper>
  <swiper-slide v-for="item in mediaItems" :key="item.id">
    ...
  </swiper-slide>
</swiper>

Obsolete slot syntax

The slot syntax has changed in Vue 2.6.0, so slot="slotName" is now v-slot:slotName, and it must be applied to a <template>:

<!-- BEFORE -->
<div class="swiper-button-prev" slot="button-prev"></div>
<div class="swiper-button-next" slot="button-next"></div>
<!-- AFTER -->
<template v-slot:button-prev>
  <div class="swiper-button-prev"></div>
</template>
<template v-slot:button-next>
  <div class="swiper-button-next"></div>
</template>

Missing next/prev button handlers

Your next/prev buttons have no click-event handlers, so they do nothing. You could add a template ref to the vue-awesome-swiper element, and get its swiperInstance prop to get at the active swiper instance. Then, use swiper.slideNext() and swiper.slidePrev() for the next and prev buttons, respectively.

<swiper ref="swiper">
  <template v-slot:button-prev>
    <div class="swiper-button-prev"
         @click="$refs.swiper.swiperInstance.slidePrev()"></div>
  </template>
  <template v-slot:button-next>
    <div class="swiper-button-next"
         @click="$refs.swiper.swiperInstance.slideNext()"></div>
  </template>
</swiper>

demo

Upvotes: 3

Related Questions