本日もお疲れ様です。現役テックキャンプ受講生のアプリ開発Day12です。最近昼夜逆転気味なり、更新も遅い時間になりがちです。いつかのタイミングで生活リズムを戻さねばと思ってます。
今日はjsによるカウントダウンを作成しました。現在、ディスカッションのためのWebアプリを作成しているのですが、ディスカッションするためのルームを一定時間経過後、自動的に閉じるように設定しようと思ってます。そのためのカウントダウンを作成していたのですが、1つのページで複数の異なるカウントダウンを表示させる方法が検索でもなかなか出てこなかったので、ここでアウトプットします。
イメージはこちらをご覧ください
https://gyazo.com/87f473586453759e904aa1ebfaa9629c
今回はRoomを複数作成し、それぞれにカウントダウンを表示させる方法について説明します。
結論はカウントダウンを作る記述をforループ内に記述すると簡単にできます。
DBにdeadline(締切)カラムを追加
締切の日付を登録するためのdatetime型のカラムを追加します。
class CreateRooms < ActiveRecord::Migration[6.1]
def change
create_table :rooms do |t|
t.string :name, null: false
t.datetime :deadline
t.timestamps
end
end
end
コントローラーにdeadline登録のための記述をする
今回、全てのルームは作成した瞬間から、三日後に自動で閉じるようにします。従って、Time.nowで現在時間を取得し、Time.now+3.daysで三日後の日付を取得します。
def create
@room = Room.new(room_params)
if @room.save
redirect_to room_path(@room)
else
render 'new'
end
end
private
def room_params
params.require(:room).permit(:name).merge(user_ids: [current_user.id],deadline:Time.now+3.days)
end
htmlをjsが利用しやすいように変更
主に、IDの追加やClass名を編集し、後程のjsで利用しやすいようにします。
まず、コントローラーでRoom全てを取得し、htmlに出力します。
def index
@rooms = Room.all
end
<% @rooms.each do |room| %>
<%= room.name%>
残り時間:
<div class="deadline" id="<%=room.id%>" style="display:none;">
<%=room.deadline%> # この記述でRoomのデットラインを取得
</div>
<span id="hour<%=room.id%>"></span>時間
<span id="min<%=room.id%>"></span>分
<span id="sec<%=room.id%>"></span>秒
<% end %>
3つのspanは後程、jsで処理した出力結果を入れるための箱になります。
js
順番に確認していきます。その前に大変お世話になったサイト↓
①ページが読み込まれた段階で、jsを起動するための記述をします。
function countdown(){
}
window.addEventListener('load',countdown); // これでロード時にcountdown関数が起動。
②今の時間を取得し、deadlineのClassを取得します。今回取得するdeadlinesはRoomの数を数えるための取得でもあるので、あえてidではなくclassで取得します。
function countdown(){
const now = new Date();//今の時間
const deadlines = document.getElementsByClassName("deadline");//deadlineを配列で取得
}
③forループでRoomの数だけ、残り時間を計算するようにします。ここで難しい点は2つ。
・"new Date(記述)"で文字情報の日付をデータタイム形式の日付に変更します。
・”(new Date(deadlines[i].textContent) - now)”で締切と現時間との差を計算しています。計算結果はミリ秒(1000m秒=1秒)になります。
ついでに、”getAttribute("id")”でhtml仕込んでいたIDも取得します。
function countdown(){
const now = new Date();//今の時間
const deadlines = document.getElementsByClassName("deadline");//deadlineを取得
for(let i = 0; i < deadlines.length; i++){
const differ = (new Date(deadlines[i].textContent) - now);//今回は3日後まであと何ミリ秒か
const differ_id = deadlines[i].getAttribute("id")
};
}
④秒、分、時間を計算します。
(中略)
const sec=Math.floor(differ/1000)%60;
const min=Math.floor(differ/1000/60)%60;
const hour=Math.floor(differ/1000/60/60);
(中略)
//ちなみに日を測りたい場合は
//const hour=Math.floor(differ/1000/60/60)%24;
//const day=Math.floor(differ/1000/60/60/24);
⑤htmlにjsで処理した結果を入力します。padStartは1桁になった場合に頭に0をつけてくれるものです。
//(中略)
document.getElementById("hour"+differ_id).textContent=String(hour).padStart(2,"0"); //一桁になった時0がつくように
document.getElementById("min"+differ_id).textContent=String(min).padStart(2,"0")
document.getElementById("sec"+differ_id).textContent=String(sec).padStart(2,"0")
⑥最後に2秒ごとに時間の表示を変更させます。
function countdown(){
const now = new Date();//今の時間
const deadlines = document.getElementsByClassName("deadline");//deadlineを取得
// console.log(deadlines[0].getAttribute("id"))
for(let i = 0; i < deadlines.length; i++){
const differ = (new Date(deadlines[i].textContent) - now);//3日後まであと何ミリ秒か
const differ_id = deadlines[i].getAttribute("id")
const sec=Math.floor(differ/1000)%60;
const min=Math.floor(differ/1000/60)%60;
const hour=Math.floor(differ/1000/60/60);
document.getElementById("hour"+differ_id).textContent=String(hour).padStart(2,"0"); //一桁になった時0がつくように
document.getElementById("min"+differ_id).textContent=String(min).padStart(2,"0")
document.getElementById("sec"+differ_id).textContent=String(sec).padStart(2,"0")
};
setTimeout(countdown,1000);//forループの外側に記述
}
window.addEventListener('load',countdown);
参考サイト