質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
JavaScript

JavaScriptは、プログラミング言語のひとつです。ネットスケープコミュニケーションズで開発されました。 開発当初はLiveScriptと呼ばれていましたが、業務提携していたサン・マイクロシステムズが開発したJavaが脚光を浴びていたことから、JavaScriptと改名されました。 動きのあるWebページを作ることを目的に開発されたもので、主要なWebブラウザのほとんどに搭載されています。

Q&A

解決済

1回答

1284閲覧

タイマー機能を複数個実装したい

knight1220

総合スコア23

JavaScript

JavaScriptは、プログラミング言語のひとつです。ネットスケープコミュニケーションズで開発されました。 開発当初はLiveScriptと呼ばれていましたが、業務提携していたサン・マイクロシステムズが開発したJavaが脚光を浴びていたことから、JavaScriptと改名されました。 動きのあるWebページを作ることを目的に開発されたもので、主要なWebブラウザのほとんどに搭載されています。

0グッド

0クリップ

投稿2020/06/24 07:18

formに目標時間を入力し、時間がきたら知らせるタイマーを作っています。
目標時間が1つの時は実現したい挙動をしてくれるのですが、目標時間を複数個設定すると最後に設定した時間しかタイマーとして機能しなくて困っています。
現状は目標時間を複数個設定すると前に設定した目標時間へのカウントダウンが止まり最後に入力したタイマーのみ正常に動いている状態です。
※すべてのカウントダウンが止まることなくカウントしたい。

html

1<form action="#" id="goal_time"> 2 <input type="text" name="set_hours" list="hours_" class="input"><span class="hours_span"></span> 3 4 <input type="text" name="set_mins" list="mins_" class="input"><span class="mins_span"></span> 5 6 <input type="text" name="set_secs" list="secs_" class="input"><span class="secs_span"></span> 7 8 <br> 9 <br> 10 <span class="remind_span">リマインド</span><textarea type="text" name="memo" class="textarea"></textarea><span></span> 11 <br> 12 <input type="button" value="決定" id="set_" class="submit-btn"><!--enterで送信させないようにわざとtypeをbuttonにしている--> 13 </form> 14 <div id="remind_list"> 15 </div>

JavaScript

1let clickCount=0; 2let goal=new Date; 3 4 let gTimer=function(event){ 5 event.preventDefault();//タグの基本動作をキャンセルする 6 7 clickCount++;// クリックされるごとにカウントアップ 8 console.log(clickCount); 9 10 let gHours=Number( document.getElementById('goal_time').set_hours.value ); 11 let gMins=Number( document.getElementById('goal_time').set_mins.value ); 12 let gSecs=Number( document.getElementById('goal_time').set_secs.value ); 13 14 goal.setHours(gHours); 15 goal.setMinutes(gMins); 16 goal.setSeconds(gSecs); 17 18 19 //クリックされるごとにpタグを作成 20 let newElementP=document.createElement('p'); 21 newElementP.id=clickCount; 22 let setPosition=document.getElementById('remind_list'); 23 setPosition.appendChild(newElementP); 24 25 function countdown(){ 26 const now=new Date; 27 const rest=goal.getTime()-now.getTime(); 28 const sec=Math.floor(rest/1000)%60; 29 const min=Math.floor(rest/1000/60)%60; 30 const hour=Math.floor(rest/1000/60/60)%24; 31 const day=Math.floor(rest/1000/60/60/24); 32 const count=[day,hour,min,sec]; 33 return count; 34 } 35 36 function recalc(){ 37 const counter=countdown(goal); 38 let restHours=counter[1]; 39 let restMins=counter[2]; 40 let restSecs=counter[3]; 41 let time=`残り時間:${counter[1]}時間${counter[2]}${counter[3]}`; 42 43 if( restHours === 0 && restMins === 0 && restSecs === 0 ){ 44 document.getElementById(clickCount).textContent='時間です'; 45 clearInterval(timer) 46 function flashing(){ 47 document.getElementById(clickCount).classList.toggle('timeOverColor'); 48 } 49 let timeOver=window.setInterval(flashing,1000); 50 function timeOverClear(){ 51 clearInterval(timeOver); 52 } 53 setTimeout(timeOverClear,5000); 54 }else{ 55 document.getElementById(clickCount).textContent=time; 56 } 57 58 if( restHours === 0 && restMins === 0 && restSecs === 0 ){ 59 clearInterval(timer); 60 let childWindow = window.open( '', 'reminder', 'width=300,height=300' ); 61 let cWdocument=childWindow.document; 62 //子wiondowのhtml 63 cWdocument.write('<html><head><title>時間です</title>'); 64 cWdocument.write('<title>時間です</title>'); 65 cWdocument.write('<link rel="stylesheet" href="./css/style.css">'); 66 cWdocument.write('</head>'); 67 cWdocument.write('<body>'); 68 cWdocument.write( `<p id="memo">${document.getElementById('goal_time').memo.value}</p>` ); 69 cWdocument.write('</body></html>') 70 childWindow.focus(); 71 } 72 73 } 74 75 let timer=setInterval(recalc,1000); 76 77 }//gTimer end 78document.getElementById('set_').addEventListener('click',gTimer,false);

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答1

0

ベストアンサー

clickCountがクリックされるたびに更新されてしまうので、最後のものにすべて更新がかかってしまいます。
即時実行関数で囲ってクロージャ―をしています。
また、goalも外で定義されていたので、クリックされるたびに上書きされてしまいますね。
実行されたタイミングで定義されるようにしています。

JavaScript

1let clickCount = 0; 2 3let gTimer = function (event) { 4 event.preventDefault();//タグの基本動作をキャンセルする 5 6 let goal = new Date; 7 8 clickCount++;// クリックされるごとにカウントアップ 9 console.log(clickCount); 10 11 12 let gHours = Number(document.getElementById('goal_time').set_hours.value); 13 let gMins = Number(document.getElementById('goal_time').set_mins.value); 14 let gSecs = Number(document.getElementById('goal_time').set_secs.value); 15 16 goal.setHours(gHours); 17 goal.setMinutes(gMins); 18 goal.setSeconds(gSecs); 19 20 (function (clickCount) { 21 22 //クリックされるごとにpタグを作成 23 let newElementP = document.createElement('p'); 24 newElementP.id = clickCount; 25 let setPosition = document.getElementById('remind_list'); 26 setPosition.appendChild(newElementP); 27 28 function countdown() { 29 const now = new Date; 30 const rest = goal.getTime() - now.getTime(); 31 const sec = Math.floor(rest / 1000) % 60; 32 const min = Math.floor(rest / 1000 / 60) % 60; 33 const hour = Math.floor(rest / 1000 / 60 / 60) % 24; 34 const day = Math.floor(rest / 1000 / 60 / 60 / 24); 35 const count = [day, hour, min, sec]; 36 return count; 37 } 38 39 function recalc() { 40 const counter = countdown(goal); 41 let restHours = counter[1]; 42 let restMins = counter[2]; 43 let restSecs = counter[3]; 44 let time = `残り時間:${counter[1]}時間${counter[2]}${counter[3]}`; 45 46 if (restHours === 0 && restMins === 0 && restSecs === 0) { 47 document.getElementById(clickCount).textContent = '時間です'; 48 clearInterval(timer) 49 function flashing() { 50 document.getElementById(clickCount).classList.toggle('timeOverColor'); 51 } 52 let timeOver = window.setInterval(flashing, 1000); 53 function timeOverClear() { 54 clearInterval(timeOver); 55 } 56 setTimeout(timeOverClear, 5000); 57 } else { 58 document.getElementById(clickCount).textContent = time; 59 } 60 61 if (restHours === 0 && restMins === 0 && restSecs === 0) { 62 clearInterval(timer); 63 let childWindow = window.open('', 'reminder', 'width=300,height=300'); 64 let cWdocument = childWindow.document; 65 //子wiondowのhtml 66 cWdocument.write('<html><head><title>時間です</title>'); 67 cWdocument.write('<title>時間です</title>'); 68 cWdocument.write('<link rel="stylesheet" href="./css/style.css">'); 69 cWdocument.write('</head>'); 70 cWdocument.write('<body>'); 71 cWdocument.write(`<p id="memo">${document.getElementById('goal_time').memo.value}</p>`); 72 cWdocument.write('</body></html>') 73 childWindow.focus(); 74 } 75 76 } 77 78 let timer = setInterval(recalc, 1000); 79 80 })(clickCount); 81 82}//gTimer end 83 84document.getElementById('set_').addEventListener('click', gTimer, false);

投稿2020/06/24 08:40

編集2020/06/24 08:44
退会済みユーザー

退会済みユーザー

総合スコア0

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

knight1220

2020/06/24 09:12

早速ご回答ありがとうございました。 回答いただいたコードをコピペしてみたところ希望どおりの動きとなりました。 まだなぜなのかはわかっていませんがいまから勉強していきます。 ありがとうございました。
退会済みユーザー

退会済みユーザー

2020/06/25 00:31

変数の定義するタイミングを気にしてみてください。 上書きされるとのちに変数が呼び出されると、最後の値になってしまいます。 関数の中で定義すると関数が呼び出されるタイミングで定義され、その中だけにしか有効な変数となります。 (クロージャで調べてみてください)
knight1220

2020/06/27 06:51

返信いただきありがとうございます。 即時関数については概ね理解できました。 クロージャについてはまだ少ししか理解できていませんが、何を調べればいいかわからない状態から脱却できました。 urswtlvinさんのおかげです。 ありがとうございました。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問