前提
- 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
のバージョンが違うと動かなくなるのでその都度確認してから実装してください。
後は適当にスタイルつけたら完成です。