回答編集履歴

3

テスト用コードの記述が混じっていたため、削除

2015/09/03 18:53

投稿

sounisi5011
sounisi5011

スコア697

test CHANGED
@@ -238,9 +238,7 @@
238
238
 
239
239
  */
240
240
 
241
- //var LS_KEY = 'txt_todo';
241
+ var LS_KEY = 'txt_todo';
242
-
243
- var LS_KEY = 'teratail.15262.txt_todo.2';
244
242
 
245
243
 
246
244
 

2

空、もしくはスペースのみの項目の追加を防ぐ処理を追加。またそれに伴い、改善点の位置を変更。

2015/09/03 18:53

投稿

sounisi5011
sounisi5011

スコア697

test CHANGED
@@ -122,7 +122,31 @@
122
122
 
123
123
  動作も確認しています。
124
124
 
125
- ただし、このコードには改善すべき点が数多くあるため、私ならば以下のようにします
125
+ ただし、このコードには以下に挙げる改善すべき点が数多くあます
126
+
127
+
128
+
129
+ * ToDoは項目リストなのだから、`ul`、`li`要素を利用するべき
130
+
131
+ * 項目の入力値が空、もしくはスペースのみの場合、追加を行わない方が利便性が向上する。
132
+
133
+ * `onXXX`等の属性を利用してイベントを登録する方法は、イベントを重複して登録できない等の問題からあまり使用するべきではない。
134
+
135
+ (このコードでは重複登録はないが、利用者のアドオン等がそのような実装になっている場合も。その場合、利用者のアドオンが正常に動作しない可能性が考えられる)
136
+
137
+ [addEventListener](https://developer.mozilla.org/ja/docs/Web/API/EventTarget/addEventListener)(Internet Explorer 8以前に対応するなら、[attachEvent](https://developer.mozilla.org/ja/docs/Web/API/EventTarget/addEventListener#Compatibility)も併用)を利用したほうが良い。
138
+
139
+ * `innerHTML`は重い。このため、[document.createElement](https://developer.mozilla.org/ja/docs/Web/API/Document/createElement)等でHTMLに対応するDOMを生成するか、[insertAdjacentHTML](https://developer.mozilla.org/ja/docs/Web/API/Element/insertAdjacentHTML)を利用した方が良い。
140
+
141
+ * `window.localStorage`オブジェクトは全てのブラウザが対応しているわけではない。`window.localStorage`を利用する処理を行う前に、これに対応しているか検証するべき。
142
+
143
+ * localStorageにはHTMLを直接保存するより、JavaScript側で配列を作成し、その配列に項目の情報を入れ、それを[JSON.stringify](https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/JSON/stringify)で[JSON](https://ja.wikipedia.org/wiki/JavaScript_Object_Notation)に変換し、保存したほうが良い。これにより、利用者のハードディスクの使用量を軽減できる。
144
+
145
+ なお、[JSON](https://ja.wikipedia.org/wiki/JavaScript_Object_Notation)から配列に戻す場合は[JSON.parse](https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/JSON/parse)を使用。
146
+
147
+
148
+
149
+ このため、私ならば以下のようにコードを書きます。
126
150
 
127
151
  (下記コードはInternet Explorer 8以前には対応していません。対応する必要がある場合はコメントをお願いします。)
128
152
 
@@ -214,7 +238,9 @@
214
238
 
215
239
  */
216
240
 
217
- var LS_KEY = 'txt_todo';
241
+ //var LS_KEY = 'txt_todo';
242
+
243
+ var LS_KEY = 'teratail.15262.txt_todo.2';
218
244
 
219
245
 
220
246
 
@@ -226,51 +252,139 @@
226
252
 
227
253
  function add_todo() {
228
254
 
255
+ var value;
256
+
257
+ var item_value;
258
+
259
+
260
+
229
261
  /**
230
262
 
263
+ * 入力欄の入力値を取得
264
+
265
+ */
266
+
267
+ var value = document.getElementById('txt_todo').value;
268
+
269
+
270
+
271
+ /**
272
+
273
+ * 入力値が空、あるいはスペースのみの場合、項目を追加しない
274
+
275
+ */
276
+
277
+ if (value.trim() !== '') {
278
+
279
+ /**
280
+
231
- * 入力欄の入力値を取得し、Stringオブジェクトに変換
281
+ * 入力欄の入力値をStringオブジェクトに変換
282
+
283
+ *
284
+
285
+ * Note: ここでStringオブジェクトに変換しているのは、重複した値を持つ項目を識別するため
286
+
287
+ * プリミティブ値(普通の文字列)では同じ値の項目を区別できないが、
288
+
289
+ * オブジェクトは区別できる
290
+
291
+ */
292
+
293
+ item_value = new String(value);
294
+
295
+
296
+
297
+ /**
298
+
299
+ * ToDoの情報を配列に追加
300
+
301
+ */
302
+
303
+ todo_items.push(item_value);
304
+
305
+
306
+
307
+ /**
308
+
309
+ * HTML内に要素を追加する
310
+
311
+ */
312
+
313
+ add_item_elem(item_value);
314
+
315
+
316
+
317
+ /**
318
+
319
+ * データを保存
320
+
321
+ */
322
+
323
+ save();
324
+
325
+ }
326
+
327
+ }
328
+
329
+
330
+
331
+ /**
332
+
333
+ * ToDoの項目をHTML内に挿入する関数
334
+
335
+ * @param {!String} item_value 挿入する項目の値
336
+
337
+ */
338
+
339
+ function add_item_elem(item_value) {
340
+
341
+ var item_elem;
342
+
343
+ var item_del_button_elem;
344
+
345
+
346
+
347
+ /**
348
+
349
+ * この処理は、項目に対応する以下のHTMLを生成しています
350
+
351
+ * (厳密には異なります)
232
352
 
233
353
  *
234
354
 
235
- * Note: ここでStringオブジェクトに変換しているのは、重複した値を持つ項目を識別するため
355
+ * <li>
236
-
237
- * プリミティブ値(普通の文字列)では同じ値の項目を区別できないが、
356
+
238
-
239
- * オブジェクトは区別できる
357
+ * {item_value}
358
+
359
+ * <input type=button value=del onclick=del_todo>
360
+
361
+ * </li>
240
362
 
241
363
  */
242
364
 
365
+ item_elem = document.createElement('li');
366
+
367
+ item_elem.appendChild(document.createTextNode(item_value + ''));
368
+
243
- var item_value = new String(document.getElementById('txt_todo').value);
369
+ item_del_button_elem = document.createElement('input');
370
+
371
+ item_del_button_elem.type = 'button';
372
+
373
+ item_del_button_elem.value = 'del';
374
+
375
+ item_del_button_elem.addEventListener('click', del_todo_create(item_value), false);
376
+
377
+ item_elem.appendChild(item_del_button_elem);
244
378
 
245
379
 
246
380
 
247
381
  /**
248
382
 
249
- * ToDoの情報配列に追加
383
+ * HTML挿入
250
384
 
251
385
  */
252
386
 
253
- todo_items.push(item_value);
387
+ document.getElementById('view_todo').appendChild(item_elem);
254
-
255
-
256
-
257
- /**
258
-
259
- * HTML内に要素を追加する
260
-
261
- */
262
-
263
- add_item_elem(item_value);
264
-
265
-
266
-
267
- /**
268
-
269
- * データを保存
270
-
271
- */
272
-
273
- save();
274
388
 
275
389
  }
276
390
 
@@ -278,61 +392,67 @@
278
392
 
279
393
  /**
280
394
 
281
- * ToDoの項目をHTML内に挿入する関数
282
-
283
- * @param {!String} item_value 挿入する項目の値
284
-
285
- */
286
-
287
- function add_item_elem(item_value) {
288
-
289
- var item_elem;
290
-
291
- var item_del_button_elem;
292
-
293
-
294
-
295
- /**
296
-
297
- * この処理は、項目に対応する以下のHTMLを生成しています
298
-
299
- * (厳密には異なります)
300
-
301
- *
302
-
303
- * <li>
304
-
305
- * {item_value}
306
-
307
- * <input type=button value=del onclick=del_todo>
308
-
309
- * </li>
310
-
311
- */
312
-
313
- item_elem = document.createElement('li');
314
-
315
- item_elem.appendChild(document.createTextNode(item_value + ''));
316
-
317
- item_del_button_elem = document.createElement('input');
318
-
319
- item_del_button_elem.type = 'button';
320
-
321
- item_del_button_elem.value = 'del';
322
-
323
- item_del_button_elem.addEventListener('click', del_todo_create(item_value), false);
324
-
325
- item_elem.appendChild(item_del_button_elem);
326
-
327
-
328
-
329
- /**
330
-
331
- * HTMLを挿入
332
-
333
- */
334
-
335
- document.getElementById('view_todo').appendChild(item_elem);
395
+ * 「HTML内のToDoの項目を削除する関数」を生成する関数
396
+
397
+ *
398
+
399
+ * Note: わざわざ「削除する関数を生成する関数」を定義しているのは、
400
+
401
+ * 削除に必要な情報である項目の値(item_value)
402
+
403
+ * クロージャで保持するため
404
+
405
+ *
406
+
407
+ * @param {!String} item_value 削除する項目の値
408
+
409
+ * @return {function(Event)} HTML内のToDoの項目を削除する関数
410
+
411
+ */
412
+
413
+ function del_todo_create(item_value) {
414
+
415
+ return function (event) {
416
+
417
+ var item_elem;
418
+
419
+
420
+
421
+ /**
422
+
423
+ * ToDoの情報を配列から削除
424
+
425
+ */
426
+
427
+ todo_items = todo_items.filter(function (value) {
428
+
429
+ return value !== item_value;
430
+
431
+ });
432
+
433
+
434
+
435
+ /**
436
+
437
+ * HTML内の項目を削除
438
+
439
+ */
440
+
441
+ item_elem = event.currentTarget.parentNode;
442
+
443
+ item_elem.parentNode.removeChild(item_elem);
444
+
445
+
446
+
447
+ /**
448
+
449
+ * 保存
450
+
451
+ */
452
+
453
+ save();
454
+
455
+ };
336
456
 
337
457
  }
338
458
 
@@ -340,67 +460,103 @@
340
460
 
341
461
  /**
342
462
 
343
- * HTML内のToDoの項目を削除する関数」を生成する関数
344
-
345
- *
346
-
347
- * Note: わざわざ「削除する関数を生成する関数」を定義しているのは、
348
-
349
- * 削除に必要な情報である項目の値(item_value)を
350
-
351
- * クロージャで保持するため
352
-
353
- *
354
-
355
- * @param {!String} item_value 削除する項目の値
356
-
357
- * @return {function(Event)} HTML内のToDoの項目を削除する関数
358
-
359
- */
360
-
361
- function del_todo_create(item_value) {
362
-
363
- return function (event) {
364
-
365
- var item_elem;
366
-
367
-
368
-
369
- /**
370
-
371
- * ToDo情報を配列ら削除
372
-
373
- */
374
-
375
- todo_items = todo_items.filter(function (value) {
376
-
377
- return value !== item_value;
378
-
379
- });
380
-
381
-
382
-
383
- /**
384
-
385
- * HTML内の項目を削除
386
-
387
- */
388
-
389
- item_elem = event.currentTarget.parentNode;
390
-
391
- item_elem.parentNode.removeChild(item_elem);
392
-
393
-
394
-
395
- /**
396
-
397
- * 保存
398
-
399
- */
400
-
401
- save();
402
-
403
- };
463
+ * ページが読み込まれたら、localStorageから情報を取り出しHTMLに展開する関数
464
+
465
+ */
466
+
467
+ function load() {
468
+
469
+ var todo_json_data;
470
+
471
+ var todo_saved_data;
472
+
473
+
474
+
475
+ if (IS_SUPPORT_LS) {
476
+
477
+ /**
478
+
479
+ * localStorageからデータを読み込む
480
+
481
+ */
482
+
483
+ todo_json_data = localStorage.getItem(LS_KEY);
484
+
485
+
486
+
487
+ /**
488
+
489
+ * localStorageから正しく読み込めたか、
490
+
491
+ * またそデータが存在する判定
492
+
493
+ */
494
+
495
+ if (todo_json_data) {
496
+
497
+ try {
498
+
499
+ /**
500
+
501
+ * localStorageから読み込んだJSONをJavaScriptオブジェクトに変換
502
+
503
+ */
504
+
505
+ todo_saved_data = JSON.parse(todo_json_data);
506
+
507
+
508
+
509
+ /**
510
+
511
+ * 読み込んだデータが配列か、また配列の項目数が1以上か判定
512
+
513
+ */
514
+
515
+ if (Array.isArray(todo_saved_data) && 0 < todo_saved_data.length) {
516
+
517
+ /**
518
+
519
+ * 読み込んだデータに合わせ、HTMLを挿入
520
+
521
+ * また、データ内の文字列をStringオブジェクトに変換
522
+
523
+ *
524
+
525
+ * Note: ここでStringオブジェクトに変換しているのは、重複した値を持つ項目を識別するため
526
+
527
+ * プリミティブ値(普通の文字列)では同じ値の項目を区別できないが、
528
+
529
+ * オブジェクトは区別できる
530
+
531
+ */
532
+
533
+ todo_items = todo_saved_data.map(function (v) {
534
+
535
+ // 各項目に相当する文字列を、Stringオブジェクトに変換
536
+
537
+ var value = new String(v);
538
+
539
+
540
+
541
+ // 項目に対応するHTMLを挿入
542
+
543
+ add_item_elem(value);
544
+
545
+
546
+
547
+ // Stringオブジェクトを返す
548
+
549
+ return value;
550
+
551
+ });
552
+
553
+ }
554
+
555
+ } catch (e) { }
556
+
557
+ }
558
+
559
+ }
404
560
 
405
561
  }
406
562
 
@@ -408,101 +564,21 @@
408
564
 
409
565
  /**
410
566
 
411
- * ページが読み込まれたら、localStorageから情報を取り出しHTMLに展開する関数
567
+ * localStorage情報を保存する関数
412
-
568
+
413
- */
569
+ */
414
-
570
+
415
- function load() {
571
+ function save() {
416
572
 
417
573
  var todo_json_data;
418
574
 
419
- var todo_saved_data;
420
-
421
575
 
422
576
 
423
577
  if (IS_SUPPORT_LS) {
424
578
 
425
- /**
426
-
427
- * localStorageからデータを読み込む
428
-
429
- */
430
-
431
- todo_json_data = localStorage.getItem(LS_KEY);
432
-
433
-
434
-
435
- /**
436
-
437
- * localStorageから正しく読み込めたか、
438
-
439
- * またそのデータが存在するか判定
440
-
441
- */
442
-
443
- if (todo_json_data) {
444
-
445
- try {
446
-
447
- /**
448
-
449
- * localStorageから読み込んだJSONを配列に変換
450
-
451
- */
452
-
453
- todo_saved_data = JSON.parse(todo_json_data);
579
+ todo_json_data = JSON.stringify(todo_items);
454
-
455
-
456
-
457
- /**
580
+
458
-
459
- * 読み込んだデータが配列か、また配列の項目数が1以上か判定
460
-
461
- */
462
-
463
- if (Array.isArray(todo_saved_data) && 0 < todo_saved_data.length) {
464
-
465
- /**
466
-
467
- * 読み込んだデータに合わせ、HTMLを挿入
468
-
469
- * また、データ内の文字列をStringオブジェクトに変換
470
-
471
- *
472
-
473
- * Note: ここでStringオブジェクトに変換しているのは、重複した値を持つ項目を識別するため
474
-
475
- * プリミティブ値(普通の文字列)では同じ値の項目を区別できないが、
476
-
477
- * オブジェクトは区別できる
478
-
479
- */
480
-
481
- todo_items = todo_saved_data.map(function (v) {
581
+ localStorage.setItem(LS_KEY, todo_json_data);
482
-
483
- // 各項目に相当する文字列を、Stringオブジェクトに変換
484
-
485
- var value = new String(v);
486
-
487
-
488
-
489
- // 項目に対応するHTMLを挿入
490
-
491
- add_item_elem(value);
492
-
493
-
494
-
495
- // Stringオブジェクトを返す
496
-
497
- return value;
498
-
499
- });
500
-
501
- }
502
-
503
- } catch (e) { }
504
-
505
- }
506
582
 
507
583
  }
508
584
 
@@ -512,30 +588,6 @@
512
588
 
513
589
  /**
514
590
 
515
- * localStorageに情報を保存する関数
516
-
517
- */
518
-
519
- function save() {
520
-
521
- var todo_json_data;
522
-
523
-
524
-
525
- if (IS_SUPPORT_LS) {
526
-
527
- todo_json_data = JSON.stringify(todo_items);
528
-
529
- localStorage.setItem(LS_KEY, todo_json_data);
530
-
531
- }
532
-
533
- }
534
-
535
-
536
-
537
- /**
538
-
539
591
  * ページが読み込まれた際にload関数が実行されるよう設定
540
592
 
541
593
  * Note: この処理は以下とほぼ等価:
@@ -563,29 +615,3 @@
563
615
  </html>
564
616
 
565
617
  ```
566
-
567
-
568
-
569
- 改善点として、
570
-
571
-
572
-
573
- * ToDoは項目リストなのだから、`ul`、`li`要素を利用するべき
574
-
575
- * `onXXX`等の属性を利用してイベントを登録する方法は、イベントを重複して登録できない等の問題からあまり使用するべきではない。
576
-
577
- (このコードでは重複登録はないが、利用者のアドオン等がそのような実装になっている場合も。その場合、利用者のアドオンが正常に動作しない可能性が考えられる)
578
-
579
- [addEventListener](https://developer.mozilla.org/ja/docs/Web/API/EventTarget/addEventListener)(Internet Explorer 8以前に対応するなら、[attachEvent](https://developer.mozilla.org/ja/docs/Web/API/EventTarget/addEventListener#Compatibility)も併用)を利用したほうが良い。
580
-
581
- * `innerHTML`は重い。このため、[document.createElement](https://developer.mozilla.org/ja/docs/Web/API/Document/createElement)等でHTMLに対応するDOMを生成するか、[insertAdjacentHTML](https://developer.mozilla.org/ja/docs/Web/API/Element/insertAdjacentHTML)を利用した方が良い。
582
-
583
- * `window.localStorage`オブジェクトは全てのブラウザが対応しているわけではない。`window.localStorage`を利用する処理を行う前に、これに対応しているか検証するべき。
584
-
585
- * localStorageにはHTMLを直接保存するより、JavaScript側で配列を作成し、その配列に項目の情報を入れ、それを[JSON.stringify](https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/JSON/stringify)で[JSON](https://ja.wikipedia.org/wiki/JavaScript_Object_Notation)に変換し、保存したほうが良い。これにより、利用者のハードディスクの使用量を軽減できる。
586
-
587
- なお、[JSON](https://ja.wikipedia.org/wiki/JavaScript_Object_Notation)から配列に戻す場合は[JSON.parse](https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/JSON/parse)を使用。
588
-
589
-
590
-
591
- が挙げられます。

1

冒頭の文章で、伝わりにくいと判断した表現に加筆

2015/09/03 18:51

投稿

sounisi5011
sounisi5011

スコア697

test CHANGED
@@ -4,9 +4,9 @@
4
4
 
5
5
 
6
6
 
7
- * localStorageに対応するデータがい場合が想定できていない
7
+ * localStorageに対応するデータが保存されてない(初回利用時の)場合が想定できていない
8
-
8
+
9
- * 削除した時に保存されていない
9
+ * 項目を削除した時にデータが保存されていない
10
10
 
11
11
 
12
12