ToDoアプリの作成

Todoアプリの作成


Vue.jsを使って、簡単なToDoアプリを作ってみましょう。

次のような手順で作成していきます。

1. タスクを一覧表示するための配列を作成
2. 追加ボタンの作成(addTodoメソッド作成)
3. 完了のチェックボックス作成
4. 削除ボタン作成
5. 更新しても値がリセットされないようにする

1. 配列の中身を一覧表示してみよう


まずは、main.js に配列のデータを作成します。

<main.js>

var app = new Vue({
    el: '#app',
    data: {
        list: [
            {text: 'サンプル1'},
            {text: 'サンプル2'},
            {text: 'サンプル3'},
        ],
    },
});

<index.html>

    <div id="app">
        <ul v-for="todo in list">
            <li>{{ todo.text }}</li>
        </ul>
    </div>

解説
① main.js のlistを index.html の <ul v-for="todo in list"> で受け取り、1件づつ todo の中に入れる。
② todo.text の形で 中身の サンプル1 を出力
③ v-for を使っているので、list の中身が無くなるまで繰り返す。

 

これで配列の中身が出力されることが確認できたので、サンプルデータは削除しておきましょう。
(今後は、追加したタスクをこのlistの中にpushしていくためです)

<main.js>

var app = new Vue({
    el: '#app',
    data: {
        list: [],
    },
});

2. 追加ボタンを作成しよう


まずは処理から書いていきます。

<main.js>

var app = new Vue({
    el: '#app',
    data: {
        list: [],
        addText: '',
    },
    methods: {
        addToDo: function() {
            this.list.push({
                text: this.addText
            });
        }
    }
});

<index.html>

<div id="app">
    <input type="text" v-model="addText" placeholder="ToDoを入力して">
    <button v-on:click="addToDo()">追加</button><hr>
    <ul v-for="todo in list">
        <li>{{ todo.text }}</li>
    </ul>
</div>

解説
① dataに addText を追加する。これから追加するテキストを受け取るため。
② 「このlistにpushします。このaddTextを」という感じで、addTextを追加できるようにする。
④ 実際に addText を入力できる欄を作成する。js側の addText 紐づけたいので v-model で指定しておく。
③ ボタンが押された時に、この処理を起動させたいので v-on でボタンを作成。

微調整


これだけで追加の機能はほとんど完成なのですが、少し微調整をしておきましょう。

<その1>
「追加」のボタンが押された時に、入力欄には値がそのまま残ったままです。
まず、これが消えるようにしましょう。
→ 一行追加するだけです。

methods: {
    addToDo: function() {
        this.list.push({
            text: this.addText
        });
    //メソッドの最後にaddTextを空欄にする処理を追加するだけ
    this.addText = '';
    }
}

<その2>
空白のまま「追加」ボタンが押されると、空の予定が作成されて一覧にされてしまいます。
→ if文で分岐してあげましょう

methods: {
    addToDo: function() {
        if (this.addText !== '') {
            this.list.push({
                text: this.addText
            });
        }
        this.addText = '';
    }
}

3. 完了のチェックボックスを作成しよう


main.js の text の値に isCheckedを加えましょう。

methods: {
    addToDo: function() {
        if (this.addText !== '') {
            this.list.push({
                text: this.addText, 
                isChecked: false,
            });
        }
        this.addText = '';
    }
}

解説
① Todoを追加した瞬間は、当然タスクはまだ終わっていないので、チェックフラグは falseにしておく

<index.html>
1件分が入っているtodo のデータにある isChecked と紐づけたいので v-model を使います。
見やすくするためにここで li タグを改行しておきます。

<div id="app">
    <input type="text" v-model="addText" placeholder="ToDoを入力して">
    <button v-on:click="addToDo()">追加</button><hr>
    <ul v-for="todo in list">
        <li>
           <input type="checkbox" v-model="todo.isChecked">{{ todo.text }}
        </li>
    </ul>
</div>

チェックがついたタスクは完了したということになります。
わかりやすいように、チェックがついたタスクには打ち消し線をつけてあげることにしましょう。

CSSで { text-decoration: line-through; } を使えばOKです。
このCSSを「isCheckedがtrueなら適用する」というように書けば実現できるはずです。

vue.jsでは、クラスを付け替えたりするときに v-bind というものが使えます。
liタグの中に span タグで classを定義しておきます。
class名は done とします。

<div id="app">
    <input type="text" v-model="addText" placeholder="ToDoを入力して">
    <button v-on:click="addToDo()">追加</button><hr>
    <ul v-for="todo in list">
        <li>
            <span v-bind:class="{ done: todo.isChecked }">
                <input type="checkbox" v-model="todo.isChecked">{{ todo.text }}
            </span>
        </li>
    </ul>
</div>

<styles.css>

.done {
    text-decoration: line-through;
}

これで、打ち消し線をつけることができました!

削除ボタンを作成しよう


チェックをつけたタスクを一括で削除するボタンを作成しましょう。
今回はJavaScriptの filter を使用します。filterの使い方
→ deleteBtn を作成

<main.js>

methods: {
    addToDo: function() {
        if (this.addText !== '') {
            this.list.push({
                text: this.addText, 
                isChecked: false,
            });
        }
        this.addText = '';
    },
    deleteBtn: function() {
        this.list = this.list.filter(function(todo) {
            return !todo.isChecked;
        });
    }
}

<index.html>
→削除ボタン作成

<div id="app">
    <input type="text" v-model="addText" placeholder="ToDoを入力して">
    <button v-on:click="addToDo()">追加</button>
    <button v-on:click="deleteBtn()">削除</button><hr>
    <ul v-for="todo in list">
        <li>
            <span v-bind:class="{ done: todo.isChecked }">
                <input type="checkbox" v-model="todo.isChecked">{{ todo.text }}
            </span>
        </li>
    </ul>
</div>

解説
① deleteBtnメソッドでは、削除して消すというよりは 「チェックがついていないタスクを返して表示する」 という内容の処理を作成します。

localStorageを使って、データを永続化してみる


今、画面を更新するとすべての変更が最初の状態に戻ってしまいます。
そこで、localStorage というのを使って、データを永続的に保持できるようにしてみましょう。
localStorage は 「ブラウザにデータを保有する機能」 なので、ブラウザが更新されても、タブが閉じられても変更した内容が保持されるようになります。

この機能を実装するために必要な知識は以下の通りです。
・JSON.stringify()、JSON.parse()でJSON形式のデータを扱う
・watchでデータを監視する
・mountを使用する
※watchとmountについては、ここではあまり詳しい事は触れていません。具体的な使い方が気になる方はこちらをご覧ください。
watchについて
mountについて

JSON形式のデータをlocalStorageに保存してみる


突然JSON形式のデータと言われても…という感じなので、まずはJSON形式の例を見てみます。
次のような形です。

let user = {
    name: "太郎",
    age: "20",
    email: "sample.com"
}

普通のオブジェクトと同じに見えますよね。実はそうなんです。
JSONとは「 JavaScript Object Notation 」の略でオブジェクトのデータ構造をしているものなのです。
ではさっそく、このJSONを localStorage に保存してみましょう。

localStorage にデータを保存するには、 setItem()を使います。

localStorage.setItem(key, value); //keyとvalueをペアにする

localStorage からデータを取り出すには、 getItem()を使います。

localStorage.getItem(key); //keyに対応するvalueを取得
let user = {
    name: "太郎",
    age: "20",
    email: "sample.com"
}

localStorage.setItem("user", user);
localStorage.getItem("user");

ブラウザを更新したら、デベロッパーツール → Application → Local Storage → file:// を開いてください。

Value の箇所が object Object となっています。つまり、JSON形式のままデータが保存されてしまっているので、
文字列に変換する必要があります

JSON.stringify()、JSON.parse()でJSONを文字列に変換する


//JSON形式 → 文字列
localStorage.setItem("user", JSON.stringify(user));
//データを取得
JSON.parse(localStorage.getItem("user"));

【完成系】

let user = {
    name: "太郎",
    age: "20",
    email: "sample.com"
}

localStorage.setItem("user", JSON.stringify(user));
JSON.parse(localStorage.getItem("user"));

こうすると、先ほどまで object Object となっていた部分が、文字列の形で保存されるようになりました!

watchでデータを監視する


vue.jsには ウォッチャ という機能があります。
よくある解説には 「特定のデータまたは算出プロパティの状態を監視して、変化があったとき登録した処理を自動的に実行する」 とあります。
watchの基本的な形は次のように記述します。

【基本形】

watch: {
    変更を監視するプロパティ名: function(変更後の値, 変更前の値) {
        // 処理
    }
}

解説
監視するプロパティに変更があった場合、functionで指定した処理を実行するという機能です。

【今回のToDoアプリの場合】

watch: {
    list: {
        handler: function() {
            localStorage.setItem("list", JSON.stringify(this.list));
        },
        deep: true
    }
},

解説
handler と deep: true という記述が出てきました。
watchを使用する時「 ネストされたオブジェクトは監視対象から外れてしまう 」ということに注意する必要があります。
ネストされたオブジェクト形式というのは、次のような形です。

mountについて


mountedに関数を記述することで、画面ロード時に好きな処理を実行させることができます。
今回は、mountの中にはLocalStorageに追加されたデータを読み込む処理を記述します。

mounted: function() {
    this.list = JSON.parse(localStorage.getItem("list")) || [];
}

解説
|| []; で空の配列をつけているのは、localStorageが空だった場合、this.list にnullを設定してしまうのを防ぐためです。
nullは配列ではないので、pushなどの関数を使おうとするとエラーになります。
そのため、this.listがnullの場合は空の配列を代入するようにしています。
デベロッパーツールで見てみると、listが空の時は、valueが [] になっているのが確認できます。

試しに以下のように|| [] を無しで書くとエラーになることを確認しておきましょう。

this.list = JSON.parse(localStorage.getItem("list")) ;

Consoleでエラーを確認しておきます。

ここまでで、全体のコードは次のような形になります。

var app = new Vue({
    el: '#app',
    data: {
        list: [],
        addText: '',
    },
    //watchでlistの変更を監視
    watch: {
        list: {
            handler: function() {
                //localStorageにデータを保存
                localStorage.setItem("list", JSON.stringify(this.list));
            },
            deep: true
        }
    },
    //マウントされた時にlocalStorageからデータを取得
    mounted: function() {
        this.list = JSON.parse(localStorage.getItem("list")) || [];
    },
    methods: {
        addToDo: function() {
            if (this.addText !== '') {
                this.list.push({
                    text: this.addText, 
                    isChecked: false,
                });
            }
            this.addText = '';
        },
        deleteBtn: function() {
            this.list = this.list.filter(function(todo) {
                return !todo.isChecked;
            });
        }
    }
});

これで、追加削除した内容がブラウザに保存されるので、更新をかけても編集した内容がリセットされることはなくなりました!
Local Storage → file:// の画面に更新マークがあるのでそこからリセットすることもできます。

まとめ


今回は、ToDoアプリ作成のために以下の内容を見てきました。
v-for:タスク一覧表示のために使用
・methods:追加ボタン作成のためにlistにpushする機能の実装
v-bind:完了のタスクにCSSのクラスを適用させるために使用
・filter ← JavaScriptの機能で削除ボタンの実装


(実はここから下は、ToDoアプリ作成に直接必須の機能ではありません)
・localStorageでデータの永続化
・watch
・mount

今回、Vue.jsを書く準備としてscriptタグを読み込みましたね。
しかし、実際の開発現場では「Vue CLI」というのを導入して開発を進めるのが一般的です。
JavaScritp3章では以下の内容はあまり詳しく解説はしていません。
・コンポーネント
・フック
・watch
・mount
など。

カテゴリー

アーカイブ

Close Bitnami banner
Bitnami