「TODOリスト」プログラムを作る!
腕試しとして、jQueryとJavaScriptでシンプルなプログラムを作ってみましょう
初心者向けのプログラムで「TODOリスト」をよく作るらしいので、
やってみましょう!
どう実装するか考えてみましょう。
まずは要件と実装方法からです!
「TODOリスト」プログラムの要件と実装方法は?
「TODOリスト」プログラムの要件
まずは使ったことがないとイメージが湧かないと思います。
まずはスマホアプリなどで実際に使ってみましょう。
その上で今回のTODOリストは次の仕様とします。
- ブラウザ上で動作する
- 「タスクの追加」ボタンがあり、押すとリストにタスクが表示される
- タスクには名称をつけて管理することができる
- 新規タスクは最上部に追加される
- タスクは完了したら「
買い物する」のように横線を引き完了したことを表現する - 完了したものは最下部に移動する
- 上記の「完了」とは別に「削除」がありタスク自体を消すことができる
- タスクリストはページをリロードしても保持される
複雑そうなTODOリストというプログラムであっても、上記のようにどのような機能を持っているのか言語化してリストにすれば、それを一つづつ実装していけば実現できます。
技術と実現手段を考える
具体的にどんな技術を使うか考えてみましょう。
- HTML/CSS/JavaScriptでブラウザで動くプログラムとする
- jQueryを使用する
- リストを表示するエリア「ul」を設置する
- タスク内容を入力するinputエリアを配置
- 「新規タスク追加」ボタンを配置
- タスクにはチェックボックスをつける(初期はチェックなし)
- チェックボックスにチェックが入ったらタスクは完了扱いとなり、横棒がひかれる(sタグ)
- タスクには削除ボタンが付いており、クリックするとタスクが削除される
- タスクリストの保存はlocalstorageで行う
- タスクの保存はユーザーが何かしたタイミングで都度自動保存を行う
こんな感じです。
HTML/CSS/JavaScriptで要素を作る
では組んでいきます。
基礎ファイル HTML/CSS/JS (jQuery読み込み済)
上記を最初のファイルとします。
HTML
<h1>タスクリスト</h1> <p><input id="taskName" type="text"> <button id="taskAdd">タスクを追加する</button> <ul id="todoList"></ul>
必要な要素はこれだけです。あとの必要な要素はJavaScriptで生成します。
ボタンをクリックしたらタスクが追加されるスクリプト
$("#taskAdd").click(function () { let taskName = $("#taskName").val(); if (!taskName) { alert("タスク名が入力されていません"); return false; } $("#todoList").prepend("<li class='incomplete'><input type='checkbox'><span>" + taskName + "</span><a href='#'>×</a></li>"); $("#taskName").val(""); });
ボタンを押すとタスク名が追加されるようにしました。
- タスクがない場合にタスク追加ができないようにする
- タスク入力したら、入力欄を空にする
という仕組みを追加しています。
次にチェックを入れたら横線を入れるという機能を追加してみます。
チェックを入れたら横線がひいて完了にする
チェックボックスにチェックが入ったら、spanタグをsタグで囲めば横線がひけます。
チェックボックスが無効になったらチェックを外す仕様にします。
$(document).on("change", "#todoList input[type='checkbox']", function () { console.log(this); if (!$(this).prop("checked")) { $(this).next().children("span").unwrap(); $(this).parent().addClass('incomplete'); $(this).parent().insertBefore("#todoList li:first-child"); } else { $(this).next().wrap("<s>"); $(this).parent().insertAfter("#todoList li:last-child"); $(this).parent().removeClass('incomplete');; } });
工夫している点として、通常は以下のように
$("#todoList input[type='checkbox']").change(function () {});
と書きますが、動的生成した要素でのトリガーは反応しなくなってしまうので、
$(document).on("change", "#todoList input[type='checkbox']", function () {});
と書く必要があります。
チェックがされている場合、されていない場合でif文により処理を分けています。
sタグで囲むと線が引かれるので「wrap()」「unwrap()」というメソッドを用いています。
「insertAfter()」「insertBefore()」により順番の並べ替えを行なっています。
×がクリックされたらタスクを削除する
このツールでは完了と削除を分けています。
理由として、終わっていることが見えないと達成感がないからです。
本当にやったか忘れる、というケースもありますね。
このへんの些細な機能が、つかやすさにかなり影響するはず・・・。
$(document).on("click", "#todoList a", function () { $(this).parent().remove(); });
一つ上の項目で紹介した通り、トリガーはこのように書かないと起動しません。
あとはremoveで消すだけです。
「消してもいいですか?」と忠告を出してから消すパターンもありますが、サクサク動くのを優先してそのような仕様はなくし、実装もシンプルにしています。
これでTODOリストの機能実装は完了です。
しかし、リロードするとデータが消えてしまうのは不便なのでブラウザの保存領域である「ローカルストレージ」にデータを保存するようにしてみます。
タスクリストの保存
localStorage.setItem("taskData",$("#todoList").html());
上記で「taskData」というkeyでデータ保存です。ユーザーが操作するたびに上記を入れます。
htmlの中身をそのままガバッと入れています。
タスクリストのロード
サイトにアクセスした際に「taskData」が存在する場合はそのデータを復元します。
let taskData = localStorage.getItem("taskData"); $("#todoList").html(taskData);
これでリストが復元されるはずです。
問題発生:チェックボックスの状態が保存できていない・・・
チェックボックスのチェックの状態が保存できていないようでした。
これはチェックボックスの状態変化がコードに反映されていないのが原因です。
チェックをつけても「checked=”checked”」というインプットタグの変化はない、ということです。
しかしチェックがついているかどうかはこちらの属性の有無で管理できるのでチェックボックスの切り替え時のスクリプトで明示的にこの属性を変化させます。
$(document).on("change", "#todoList input[type='checkbox']", function () { if (!$(this).prop("checked")) { $(this).next().children("span").unwrap(); $(this).parent().addClass('incomplete'); $(this).parent().insertBefore("#todoList li:first-child"); $(this).removeAttr("checked"); } else { $(this).next().wrap("<s>"); $(this).parent().insertAfter("#todoList li:last-child"); $(this).parent().removeClass('incomplete');; $(this).attr("checked", "checked"); } localStorage.setItem("taskData", $("#todoList").html()); });
れで想定した動きとなるはずです。
javascript全文
$(function () { let taskData = localStorage.getItem("taskData"); $("#todoList").html(taskData); $("#taskAdd").click(function () { let taskName = $("#taskName").val(); if (!taskName) { alert("タスク名が入力されていません"); return false; } $("#todoList").prepend("<li class='incomplete'><input type='checkbox'><span>" + taskName + "</span><a href='#'>×</a></li>"); $("#taskName").val(""); localStorage.setItem("taskData", $("#todoList").html()); }); $(document).on("change", "#todoList input[type='checkbox']", function () { if (!$(this).prop("checked")) { $(this).next().children("span").unwrap(); $(this).parent().addClass('incomplete'); $(this).parent().insertBefore("#todoList li:first-child"); $(this).removeAttr("checked"); } else { $(this).next().wrap("<s>"); $(this).parent().insertAfter("#todoList li:last-child"); $(this).parent().removeClass('incomplete');; $(this).attr("checked", "checked"); } localStorage.setItem("taskData", $("#todoList").html()); }); $(document).on("click", "#todoList a", function () { $(this).parent().remove(); localStorage.setItem("taskData", $("#todoList").html()); }); });
お疲れ様でした!
タスク管理アプリ
完成デモ
※データは各自のパソコンのブラウザの「ローカルストレージ」という場所に保管されています。
サーバーへの送信などは一切行われていませんので安心してご利用ください。
スマホで使いやすくする
実際ちゃんと使えそうなので、改善を加えてみました。
スマホで使いやすいようにCSSで装飾しサイズ調整しました。
reset.cssも追加しています。
Enterキーの入力でtodoが追加されるようにする
使ってみると、エンターを入力したらタスクが追加されるようにすると使いやすそうでした。
$("input[type=text]").on('keyup', function (e) { if (e.key === 'Enter' || e.keyCode === 13) { let taskName = $("#taskName").val(); if (!taskName) { alert("タスク名が入力されていません"); return false; } $("#todoList").prepend("<li class='incomplete'><input type='checkbox'><span>" + taskName + "</span><a href='#'>×</a></li>"); $("#taskName").val(""); localStorage.setItem("taskData", $("#todoList").html()); } });
上記のコードを追加して、操作性が向上しました。ぜひスマホで使ってみてください。