0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

Railsでスワイプで画像切り替えする方法

Posted at

前提

  • Ruby 2.6.3
  • Rails 6.i.3
  • Font Awesome導入済み

Bootstrapの導入

$ yarn add jquery bootstrap popper.js

インストールが出来たらenvironment.jsに以下の文を記述してください

config/webpack/environment.js
const webpack = require('webpack')
environment.plugins.append(
  'Provide',
  new webpack.ProvidePlugin({
    $: 'jquery/src/jquery',
    jQuery: 'jquery/src/jquery',
    Popper: ['popper.js', 'default']
  })
)

application.jsにも追記してください。

app/javascript/packs/application.js
import 'bootstrap';
import '../stylesheets/application';

Bootstrap導入出来ているはずです。
試しにボタンとか追加して確認してください。
Bootstrap公式ページ

application.scss作成

mkdir app/javascript/stylesheets
touch app/javascript/stylesheets/application.scss

application.html.erb追加

app/views/layouts/application.html.erb
<%= stylesheet_pack_tag 'application', 'data-turbolinks-track': 'reload' %>

Hammer.js の導入

参考ドキュメント

$ yarn add hammerjs
package.json

{
  "name": "match",
  "private": true,
  "dependencies": {
    "@fortawesome/fontawesome-free": "^5.15.3",
    "@rails/actioncable": "^6.0.0",
    "@rails/activestorage": "^6.0.0",
    "@rails/ujs": "^6.0.0",
    "@rails/webpacker": "5.2.1",
    "bootstrap": "^4.6.0",
    "hammerjs": "^2.0.8", //追記されてたらインストールできてます。
    "jquery": "^3.6.0",
    "popper.js": "^1.16.1",
    "turbolinks": "^5.2.0"
  },
  "version": "0.1.0",
  "devDependencies": {
    "webpack-dev-server": "^3.11.2"
  }
}

packs/application.jsに追加

app/javascript/packs/application.js
import 'hammerjs';

//...(省略)


require("src/swipe")

swipe.js作成

touch app/javascript/src/swipe.jsを作成します。

app/javascript/src/swipe.js

if (location.pathname == "/users") {
  $(function () {
    let allCards = document.querySelectorAll(".swipe--card");
    let swipeContainer = document.querySelector(".swipe");

    function initCards() {
      let newCards = document.querySelectorAll(".swipe--card:not(.removed)");

      newCards.forEach(function (card, index) {
        card.style.zIndex = allCards.length - index;
        card.style.transform =
          "scale(" + (20 - index) / 20 + ") translateY(-" + 30 * index + "px)";
        card.style.opacity = (10 - index) / 10;
      });
      if (newCards.length == 0) {
        $(".no-user").addClass("is-active");
      }
    }

    initCards();

    allCards.forEach(function (el) {
      let hammertime = new Hammer(el);

      hammertime.on("pan", function (event) {
        if (event.deltaX === 0) return;
        if (event.center.x === 0 && event.center.y === 0) return;

        el.classList.add("moving");

        swipeContainer.classList.toggle("swipe_like", event.deltaX > 0);
        swipeContainer.classList.toggle("swipe_dislike", event.deltaX < 0);

        let xMulti = event.deltaX * 0.03;
        let yMulti = event.deltaY / 80;
        let rotate = xMulti * yMulti;

        event.target.style.transform =
          "translate(" +
          event.deltaX +
          "px, " +
          event.deltaY +
          "px) rotate(" +
          rotate +
          "deg)";
      });
      hammertime.on("panend", function (event) {
        el.classList.remove("moving");
        swipeContainer.classList.remove("swipe_like");
        swipeContainer.classList.remove("swipe_dislike");

        let moveOutWidth = document.body.clientWidth;

        let keep = Math.abs(event.deltaX) < 200;
        event.target.classList.toggle("removed", !keep);

        if (keep) {
          event.target.style.transform = "";
        } else {
          let endX =
            Math.max(Math.abs(event.velocityX) * moveOutWidth, moveOutWidth) +
            100;
          let toX = event.deltaX > 0 ? endX : -endX;
          let endY = Math.abs(event.velocityY) * moveOutWidth;
          let toY = event.deltaY > 0 ? endY : -endY;
          let xMulti = event.deltaX * 0.03;
          let yMulti = event.deltaY / 80;
          let rotate = xMulti * yMulti;

          event.target.style.transform =
            "translate(" +
            toX +
            "px, " +
            (toY + event.deltaY) +
            "px) rotate(" +
            rotate +
            "deg)";

          initCards();
        }
      });
    });
    function createButtonListener(reaction) {
      let cards = document.querySelectorAll(".swipe--card:not(.removed)");

      if (!cards.length) return false;

      let moveOutWidth = document.body.clientWidth * 2;

      let card = cards[0];
      card.classList.add("removed");

      if (reaction == "like") {
        card.style.transform =
          "translate(" + moveOutWidth + "px, -100px) rotate(-30deg)";
      } else {
        card.style.transform =
          "translate(-" + moveOutWidth + "px, -100px) rotate(30deg)";
      }

      initCards();
    }

    $("#like").on("click", function () {
      createButtonListener("like");
    });

    $("#dislike").on("click", function () {
      createButtonListener("dislike");
    });
  });
}

index.html.erb

今回はindex.html.erbに実装しています。

users.index.html.erb
<div class="user-index-page">

  <div class="swipe">
    <div class="swipe--status">
      <i class="fa fa-times"></i>
      <i class="fa fa-heart"></i>
    </div>

    <div class="swipe--cards">
      <% @users.each do |user| %>
        <div class="swipe--card" id="<%= user.id %>">
          <% if user.profile_image.url.nil? %>
            <div class="profile-default-img"></div>
          <% else %>
            <%= image_tag user.profile_image.url, class: "profile-img" %>
          <% end %>
          <p class="profile-name">
            <%= user.name %>
          </p>
        </div>
      <% end %>
      <div class="no-user">近くにお相手がいません</div>
    </div>

    <div class="swipe--buttons">
      <button id="dislike"><i class="fas fa-times fa-2x"></i></button>
      <button id="like"><i class="fas fa-heart fa-2x"></i></button>
    </div>
  </div>

</div>

これで完成です。
Railsのバージョンが違うと動かなくなるのでその都度確認してから実装してください。
後は適当にスタイルつけたら完成です。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?