これでどうでしょうか。
修正
タイマーをオブジェクトとして正しく扱うようにしました。
デザインについては自信がありません:-)
HTML
1<!DOCTYPE HTML>
2<html>
3<head>
4<meta charset="utf-8">
5<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no">
6<meta http-equiv="Content-Security-Policy" content="default-src * data:; style-src * 'unsafe-inline'; script-src * 'unsafe-inline' 'unsafe-eval'">
7<!-- <script src="components/loader.js"></script>
8<link rel="stylesheet" href="components/loader.css">
9<link rel="stylesheet" href="css/style.css"> -->
10<style>
11.numeric {
12 text-align : right;
13}
14
15.container {
16 vertical-align : middle;
17 padding : 10px;
18 border : 1px solid;
19 margin : 5px;
20}
21
22#buttonGroup {
23 margin : 5px;
24}
25</style>
26</head>
27<body>
28 <br>
29 <form name="timer">
30 <span class="container">
31 <label id="label0">タイマー1</label>
32 <input type="text" value="" class="numeric" id="minBox0" size="2">分
33 <input type="text" value="" class="numeric" id="secBox0" size="2">秒
34 </span>
35
36 <span class="container">
37 <label id="label1">タイマー2</label>
38 <input type="text" value="" class="numeric" id="minBox1" size="2">分
39 <input type="text" value="" class="numeric" id="secBox1" size="2">秒
40 </span>
41
42 <span class="container">
43 <label id="label2">タイマー3</label>
44 <input type="text" value="" class="numeric" id="minBox2" size="2">分
45 <input type="text" value="" class="numeric" id="secBox2" size="2">秒
46 </span>
47
48 <br>
49 <br>
50
51 <div id="buttonGroup">
52 <input type="button" value="スタート" id="starter" onclick="startTimers()">
53 <input type="button" value="ストップ" id="stopper" onclick="stopTimers()">
54 </div>
55 </form>
56<script>
57var starter = document.querySelector('#starter');
58var stopper = document.querySelector('#stopper');
59
60
61//タイマーインスタンスを格納する配列
62var timerArray = [
63 new Timer('label0', 'minBox0', 'secBox0'),
64 new Timer('label1', 'minBox1', 'secBox1'),
65 new Timer('label2', 'minBox2', 'secBox2'),
66];
67
68
69//タイマーのコンストラクタ
70function Timer(label, minBox, secBox) {
71 this.intervalID = null; // nullのとき停止中
72 this.label = document.querySelector('#' + label);
73 this.minBox = document.querySelector('#' + minBox);
74 this.secBox = document.querySelector('#' + secBox);
75}
76
77
78//タイマー開始メソッド
79Timer.prototype.startTimer = function() {
80 this.stopTimer()
81
82 var min = this.minBox.value;
83 var sec = this.secBox.value;
84
85 if (min === "" && sec === "") {
86 alert(this.label.innerText + "に時間を設定してください!");
87 return;
88 }
89
90 min = (min === "" ? 0 : parseInt(min, 10));
91 sec = (sec === "" ? 0 : parseInt(sec, 10));
92
93 //不正な数値の場合
94 if (! isFinite(min) || ! isFinite(sec) ||
95 min < 0 || sec < 0 || (min === 0 && sec === 0))
96 {
97 alert(this.label.innerText + "に正しい時間を設定してください!");
98 return;
99 }
100
101 this.minBox.readonly = true;
102 this.secBox.readonly = true;
103
104 this.minBox.value = min;
105 this.secBox.value = sec;
106
107 this.countDown();
108};
109
110
111//カウントダウンする関数を1000ミリ秒毎に呼び出すメソッド
112Timer.prototype.countDown = function()
113{
114 //setIntervalのコールバック関数ではthisが変わるのでtimerで代用
115 var timer = this;
116
117 this.intervalID = setInterval(function() {
118 var min = parseInt(timer.minBox.value, 10);
119 var sec = parseInt(timer.secBox.value, 10);
120 var totalSec = min * 60 + sec - 1;
121
122 if (totalSec <= 0) {
123 timer.stopTimer();
124 totalSec = 0;
125 }
126
127 //残り分数はintを60で割って切り捨てる
128 timer.minBox.value = Math.floor(totalSec / 60);
129 //残り秒数はintを60で割った余り
130 timer.secBox.value = totalSec % 60;
131 }, 1000);
132};
133
134
135//タイマー停止メソッド
136Timer.prototype.stopTimer = function() {
137 if (this.intervalID !== null) {
138 clearInterval(this.intervalID);
139 this.intervalID = null;
140 }
141
142 this.minBox.readonly = false;
143 this.secBox.readonly = false;
144};
145
146
147//全タイマー開始関数
148function startTimers() {
149 for (var no in timerArray) {
150 timerArray[no].startTimer();
151 }
152}
153
154
155//全タイマー停止関数
156function stopTimers() {
157 for (var no in timerArray) {
158 timerArray[no].stopTimer();
159 }
160}
161</script>
162</body>
163</html>