4
3

More than 1 year has passed since last update.

[Rails,Javascript]モーダルウィンドウの実装

Posted at

チーム開発で活用しようと思った技術をアウトプット投稿

目的

以下のようなモーダルウィンドウの実装
商品の写真をクリックすると以下のように表示、背景の黒い部分をクリックすると戻る
スクリーンショット.png

開発環境

  • Ruby 3.1.2
  • Rails 6.1.7
  • bootstrap併用(bootstrap自体は実装機能と関係なし)

実装手順

1.モーダルの設置

モーダルを表示させたいページに以下の記述を行う
例)indexページにshowページの内容を表示したい場合はindexに記述

(例)index.html.erb
<div id="mask" class="hidden"></div>
<div id="modal" class="hidden"></div>

2.CSSの設定

今回はbootstrap併用のため
app/javascript/stylesheetsの中にproduct.cssを作成
app/javascript/packs/application内に以下を記述

application.js
import "../stylesheets/product.css"

これでproduct.cssが読み込まれるようになるのでモーダル処理の記述
#mask等の#はidで適応する箇所を指定している

product.css
/*#mask、つまり背景の設定*/
#mask {
  background-color: rgba(0, 0, 0, 0.5);/*背景色の指定*/
  position: fixed; /* スクロールで移動しないようmodalの位置を固定 */
  top: 0;
  bottom: 0;
  right: 0;
  left: 0;
  z-index: 1; /*z-index を持つ要素はより小さな要素の上に重なる*/
}

#modal {
  position: fixed;/* スクロールで移動しないようmodalの位置を固定 */
  top: 20vh; /*上端からの距離の指定、今回は画面上から20%の位置から配置*/
  left: 0; /*左からの距離の指定*/
  right: 0; /*右からの距離の指定*/
  margin: 0 auto; /*上2つと合わせ中央に配置される*/
  transform: translate(0, 0) scale(1); /*平行移動(translate)、拡大縮小(scale)の指定*/
  transition: 0.2s; /*上記trancsformに要する時間、今回は0.2秒*/
  z-index: 2; /*z-index を持つ要素はより小さな要素の上に重なる*/
  width: 50vw; /*モーダルの幅の指定、今回はvwを用いて画面の50%幅でモーダルを作成*/
  background-color: white; /*背景色*/
  border-radius: 8px; /*角の処理、指定することで丸みを帯びる*/
}

#mask.hidden {
  opacity: 0; /*透明度*/
  visibility: hidden; /*視認性、最初は隠しておきたいのでhiddenを指定*/
}

#modal.hidden {
  opacity: 0;
  visibility: hidden;
  transform: translate(0, 0) scale(0.8);
}

3.モーダル化したい部分の部分テンプレート化、及びコントローラー処理

モーダルとしてshowページを指定したいのでshowページを部分テンプレート化

また今回は商品一覧で、商品の写真をクリックした際にshowページを呼び出したいので、indexのlink_toにremote: trueを指定しJS形式で送信させる

index.html.erb
〜省略〜
<%= link_to product_path(product.id), remote: true do %>
  <%= image_tag product.get_image(180, 120), class: 'm-1 img-fluid mb-1' %>
<% end %>
〜省略〜

今回はshowページの表示だけなので、特にコントローラーに記述する必要は無いが、送信形式で表示処理を分けたい場合は以下のように記述

products_controller.rb
def show
# 〜省略〜
  respond_to do |format|
    format.html
    format.js # js形式で送信された場合はこちらが適応され、js.erbを探す
  end
# 〜省略〜
end

4.jsファイルの作成

app/views/public/products内に(要はindex,showと同じフォルダに)show.js.erbを作成

  • partial:に先程作成した部分テンプレート
  • locals:に部分テンプレート内に必要な変数を記述
show.js.erb
<!--モーダルを取得-->
var modal = document.getElementById('modal');
<!--マスクを取得-->
var mask = document.getElementById('mask');

<!--// # モーダルの中身をshowビューに置き換え-->
<!--// # 部分テンプレートを指定する-->
modal.innerHTML = '<%= escape_javascript(render partial: 'show', locals: { cart: @cart, genres: @genres, product: @product}) %>';

<!--// # hiddenを削除してモーダルとマスクを表示させる。-->
modal.classList.remove('hidden');
mask.classList.remove('hidden');

<!--// # モーダルの外側(マスク)をクリックするとhiddenクラスが書き込まれ、モーダルとマスクが再び非表示となる-->
mask.addEventListener('click', () => {
  modal.classList.add('hidden');
  mask.classList.add('hidden');
  });

これで完成です!

参照

以下記事を参照させて頂きました、ありがとうございます

4
3
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
4
3