eureka

Nuxtにvue-awesome-swiperを入れてスライドショーを実装する

1

vue-awesome-swiperの記事はたくさんあったけど、バージョンによってエラーが出たり出なかったり、地味に時間がかかったんだよね

環境

nuxt 2.14.0

インストール

早速swiperとvue-awesome-swiperを入れていきます。
※参考にしたサイトではvue-awesome-swiperのみのインストールが多かったのですが、swiper本体もインストールする必要があります。

$ yarn add swiper@5.x vue-awesome-swiper
or
$ npm i --save swiper@5.x vue-awesome-swiper

2021年1月現在でバージョン指定をせずインストールをすると下記のバージョンでインストールされます。

  • Swiper 6.4.7
  • vue-awesome-swiper 4.1.1

Swiper 6系ではページネーションやナビゲーションボタンが動作しなかったため、5系をインストールしていますgithubの公式でも5系が推奨されていました。

プラグインとして設定する

インストールしたvue-awesome-swiperをプラグインとして使用できるように設定していきます。

プラグインを作成

pluginsディレクトリ直下でswiper.jsというファイルを作成します。

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

Vue.use(VueAwesomeSwiper)

ここのimportするCSSに注意が必要です。
swiperのメジャーバージョンによってimportするパスが異なります。

  • swiper v4:swiper/dist/css/swiper.css
  • swiper v5:swiper/css/swiper.css
  • swiper v6:swiper/swiper-bundle.css

指定するCSSのパスを間違えるとこんな感じのエラーが出ます。
(最初Swiper 6系で5系用のCSSを読み込んでました・・)

Module not found: Error: Can’t resolve ‘swiper/css/swiper.css’

プラグインを登録

作成したプラグインをnuxt.config.js に登録します。

export default {
  plugins: [
    { src: '~/plugins/swiper', mode: 'client' }
  ],
}

参考にしたサイトでは下記のようにssrで指定されているものが多かったのですが、Nuxt公式にもある通り次のメジャーリリースで非推奨になるためmodeで指定するのが良いでしょう。

{ src: '~/plugins/swiper', ssr: false }

Nuxt.js 2.4 以降、プラグインのタイプを指定するために plugins のオプションとして mode が導入されました。指定可能な値は client または server です。ssr: false は mode: 'client' に改良され次のメジャーリリースで非推奨になります。

API: plugins プロパティ – NuxtJS

これで設定は終了です。

スライダーを作る

設定ができたのでスライダーを作成していきます。

<template>
  <swiper :options="swiperOption">
    <swiper-slide>Slide 1</swiper-slide>
    <swiper-slide>Slide 2</swiper-slide>
    <swiper-slide>Slide 3</swiper-slide>
  </swiper>
</template>

<script>
export default {
  data() {
    return {
      swiperOption: {
        autoplay: {
          delay: 2500,
          disableOnInteraction: false,
        },
        slidesPerView: 1,
        loop: true,
      },
    }
  },
}
</script>

<swiper-slide> の中にスライドさせたい要素を入れて、 <swiper><swiper-slide> をラップします。

スライドショーの設定はdata内でswiperOptionとして設定して、<swiper>optionsに渡すことで適用されます。

細かい設定はSwiper公式で確認できます。
Swiper

ページネーションやナビゲーションボタンを設定する

ページネーション(スライド下のドットとか)やナビゲーションボタン(次へ、前へ)を表示させる場合の追記です。

<template>
  <swiper :options="swiperOption">
    <swiper-slide>Slide 1</swiper-slide>
    <swiper-slide>Slide 2</swiper-slide>
    <swiper-slide>Slide 3</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>
</template>

<script>
export default {
  data() {
    return {
      swiperOption: {
        // 中略
        pagination: {
          el: '.swiper-pagination',
          clickable: true,
        },
        navigation: {
          nextEl: '.swiper-button-next',
          prevEl: '.swiper-button-prev',
        },
      },
    }
  },
}
</script>

テンプレートとswiperOptionに追記しました。
これだけでデフォルトのナビゲーションが表示されます。

スタイルを適用させる

スタイルは同じファイル内で設定することで上書きできます。

<template>
...
</template>

<script>
...
</script>

<style lang="scss" scoped>
// ここで上書きできる
.swiper-button-prev {
  left: 0;
}
</style>

生成されたSwiperの要素に対してスタイルを適用させたい場合(ボタンの中身など)には、子コンポーネントへのスタイル指定になるのでディープセレクタを使用する必要があります。

ディープセレクタでも>>> で効かない場合は/deep/を使用すると適用できる場合があります。

.swiper-pagination {
  /deep/ .swiper-pagination-bullet-active {
    background: #4e9100;
  }
}

追記:
SCSS記法の場合は>>>の記述が読み込まれないようなので/deep/となるようです。
また、Vueのバージョンによっては>>>/deep/も効かない場合があるので、その時は::v-deepで適用されるかもしれません。
Vue.jsでのdeep selectorの書き方

v-forでスライドさせる

上記だけでも動くのですが、せっかくvueでやるのでv-forで回したいですよね。

下記みたいな感じで簡単に3回繰り返して展開する処理にしました。APIデータとかに置き換えても同じようにできるかと思います。

<template>
  <swiper :options="swiperOption">
    <swiper-slide v-for="item in 3" :key="item">
      <span>Slide-{{ item }}</span>
    </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>
</template>

コンソールの警告が出たら

コンソールを見て下記のWarningが表示されていないか確認します。

[Vue warn]: The client-side rendered virtual DOM tree is not matching server-rendered content. This is likely caused by incorrect HTML markup, for example nesting block-level elements inside
, or missing . Bailing hydration and performing full client-side render.

クライアント側で作った仮想DOMとサーバー側のコンテンツが合っていないという内容ですね。

こちらはテンプレート側で<swiper></swiper><client-only> で囲むと解消されます。

<client-only>
  <swiper :options="swiperOption">
    <swiper-slide>スライダー1</swiper-slide>
    <swiper-slide>スライダー2</swiper-slide>
    <swiper-slide>スライダー3</swiper-slide>
  </swiper>
</client-only>

※Nuxtのバージョンがv2.9以下の場合は<no-ssr>を使用します。

client-only コンポーネント – NuxtJS

参考にしたサイトにはこれに触れていないものが結構あったのですが、NuxtのモードのSSR/SSGとか関係あるのかな?(知らんけど)

ちなみに私のはSSGです。

nextボタン、prevボタンがうまく動かなかったら

ボタンが表示されているのにクリックしても何も起こらない・・ページネーションも表示されてない・・エラーは何も出てない・・・みたいな状況になりました。

最初はSwiperのバージョンを6系でインストールしていたのですが、6系のCSSが上手く動作していないようです。5系にダウングレードすると上手く動作しました。
vue-awesome-swiperでnext、prevボタンが動作しない

この記事のインストールの通りにやっていれば正常に動くと思います。

参考にしたサイト

1