railsで実装した複数画像投稿機能で投稿された画像にswiperを適用させる

# 開発環境
Mac OS Catalina 10.15.7
ruby 2.6系
rails 6.0系

# 前提
アクティブストレージを用いた、複数枚画像投稿機能は実装済みとします。
投稿した複数の画像を、indexページなどで、swiperを用いて表示させることをゴールとします。
私が作っている写真投稿ができるアプリを例にしています。

# CDN読み込み

まずはCDNを読み込みます。
application.html.erb内のheadタグの中に下記のどちらかを追加しましょう。

```application.html.erb

# どちらかをheadタグ内に記述
<link rel="stylesheet" href="https://unpkg.com/swiper/swiper-bundle.css" />
<link rel="stylesheet" href="https://unpkg.com/swiper/swiper-bundle.min.css" />
```

下が最小限の機能で、上が全機能という違いがあります。

公式ドキュメントを全て読んだわけではないので、最小限の機能の線引きは不明ですが、ページネーションやスクロールバーなど基本的なものは最小限の機能に収まっていると書いてあったので、今回は下の最小限の方を使う事にしました。

---
次にapplication.html.erb内のbodyタグ内の最後に下記のどちらかを追加しましょう。(headタグに記述したものと合わせる必要があります。)

```application.html.erb
<script src="https://unpkg.com/swiper/swiper-bundle.js"></script>
<script src="https://unpkg.com/swiper/swiper-bundle.min.js"></script>
```

先ほども行った通り自分は下の最小限のものを選択しました。

# swiper.jsを記述

これはほぼ公式の丸パクリで、使わないとこだけ省いただけです。

```swiper.js

document.addEventListener("DOMContentLoaded", function(){
  var mySwiper = new Swiper('.swiper-container', {
    // Optional parameters
    loop: true,
  
    // If we need pagination
    pagination: {
      el: '.swiper-pagination',
    },
  
    // Navigation arrows
    navigation: {
      nextEl: '.swiper-button-next',
      prevEl: '.swiper-button-prev',
    },
  })
});

```

また、application.jsでswiper.jsを読み込むのも忘れずに

```application.js
require("@rails/ujs").start()
//require("turbolinks").start()
require("@rails/activestorage").start()
require("channels")
require('./preview')
require('./swiper')
```

# ビューに反映させる


公式を見る限り、基本はこんな感じで使うみたいです。

```
<div class="swiper-container">
  <!-- Additional required wrapper -->
  <div class="swiper-wrapper">
    <!-- Slides -->
    <div class="swiper-slide">Slide 1</div>
    <div class="swiper-slide">Slide 2</div>
    <div class="swiper-slide">Slide 3</div>
    ...
  </div>
  <!-- If we need pagination -->
  <div class="swiper-pagination"></div>

  <!-- If we need navigation buttons -->
  <div class="swiper-button-prev"></div>
  <div class="swiper-button-next"></div>

  <!-- If we need scrollbar -->
  <div class="swiper-scrollbar"></div>
</div>
```

ただrailsで、ユーザーが投稿した複数枚の画像を表示する際はeachメソッドを用いて記述しているケースが多いかと思います。(自分はそうでした。)
そのため、これをeachメソッドの例に置き換えてみるとこんな感じになります。

```index.html.erb

# 省略していますが<% @posts.each do |post| %>　〜　<% end %>内の記述です。

<div class="swiper-container">
  <div class= "swiper-wrapper img-index">
    <% post.images.each do |image| %>
      <%= image_tag image, class: "swiper-slide index-img" %>
    <% end %>
  </div>
  <div class="swiper-button-prev swiper-button-white"></div>
  <div class="swiper-button-next swiper-button-white"></div>
  <div class="swiper-pagination"></div>
</div>
```

今回はnextボタンとpreviewボタン、ページネーション機能をオプションでつけました。


今回やってみて、ポイントとしては4つあるかなと思いました。
・imageタグのクラスを"swiper-slide"にすること
・imagesのeachメソッドを囲う(入れ子にする)ようにswiper-wrapperクラスを持つdivタグを設置すること
・さらにswiper-containerクラスを持つdivタグを、swiper-wrapperクラスを持つdivタグのすぐ上から囲う(入れ子にする)ように設置すること
・オプションのボタンやページネーションなどは、swiper-containerクラスを持つdivタグないに設置すること


---

自分の場合は画像が複数の時と単数の時で表示させるビューをわけたいので、最終的にコードはこんな感じになりました。

```index.html.erb
<% if post.images.length < 2 %>
  <% post.images.each do |image| %>
    <%= image_tag image, class: "post-img"%>
  <% end %>
<% else %>
  <div class="swiper-container">
    <div class= "swiper-wrapper img-index">
      <% post.images.each do |image| %>
        <%= image_tag image, class: "swiper-slide index-img" %>
      <% end %>
    </div>
    <div class="swiper-button-prev swiper-button-white"></div>
    <div class="swiper-button-next swiper-button-white"></div>
    <div class="swiper-pagination"></div>
  </div>
<% end %>
```

indexページのビューはこんな感じ
思い通りに表示させることができました。
![スクリーンショット 2021-01-26 0.52.41.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1035658/ad3986c0-7bb9-5f23-ceea-e614f805aea4.png)

ちなみにswiper-button-whiteをswiper-button-blackにすると、ボタンの色が黒くなったりもします。
参考になれば幸いです。

おしまい