Vue.jsで、SPAのToDoアプリを作成してみた

はじめに

この本を参考にして、Vue.jsで、SPA(Single Page Application)のToDoアプリを作ってみました。

今回作成したもの

See the Pen Untitled by Shibata Hiroki (@khiro-enginner) on CodePen.

動き

  • することを入力して「追加」を押すと、ToDoリストが表示される
  • ToDoリストにチェックを入れると、取り消し線が表示され、処理済み件数が増える
  • 「処理済みを削除」を押すと、取り消し線がついているToDoが削除される

ソースコード

HTML・JavaScript(JS)・CSSが関連し合って、ToDoアプリが実現しています。

HTML

headタグ内で、3系のvue.jsを読み込んでいます。

// 省略 

 <script src="https://unpkg.com/vue@3/dist/vue.global.js"></script>
</head>

// 省略 

以下のような中身を書いています。

See the Pen Untitled by Shibata Hiroki (@khiro-enginner) on CodePen.

JS

Vue.jsは以下のように記述しています。

See the Pen Untitled by Shibata Hiroki (@khiro-enginner) on CodePen.

CSS

CSSで見た目を調整しています。

See the Pen Untitled by Shibata Hiroki (@khiro-enginner) on CodePen.

することを追加する機能

See the Pen Untitled by Shibata Hiroki (@khiro-enginner) on CodePen.

具体例

例えば、「食材を購入する」というToDoを「すること」に入力して「追加」を押すと、入力した文字が消え、入力欄の下に「食材を購入する」というToDoが追加されます。そして、全体の件数が1増えます。

ToDoの追加
「追加」を押した後

また、「メルカリで出品する」というような2つ目のToDoを追加することもできます(いくらでも追加できます)。

このように、することを追加する 機能について見ていきます。

文字を入力したとき

文字を入力すると、入力した文字が、v-model.trim="addtext" によって、addtext という変数に入ります。trimがあるので、空白は取り除かれます。

<input class="todo__input" type="text" v-model.trim="addtext" placeholder="すること">

addtextは、data関数として、最初は空白の状態で定義されています。

data() {
 return {
   addtext: "",
   todos: []
  };
},

入力欄に「食材を購入する」と入力したときには、addtext="食材を購入する" となります。

追加ボタンを押したとき

「追加」ボタンを押すと、v-on:click="addToDo" によって、addToDo という関数が実行されます。

<button v-on:click="addToDo">追加</button>

addToDo は、メソッドとして定義されています。もし addtext があれば、todos{ done: false, text: this.addtext } を追加して、addtextを空にするという処理です。

methods: {
 addToDo: function () {
  if (this.addtext) {
   this.todos.push({ done: false, text: this.addtext });
   this.addtext = "";
  }
 },
 cleanToDo: function () {
   this.todos = this.todos.filter(function (val) {
    return val.done == false;
   });
 }
}

入力欄に「食材を購入する」と入力した状態で「追加」ボタンを押すと、todos = [ { done: false, text: "食材を購入する" } ] となります。そして、入力欄が空になります。

ToDoが表示される

v-for="todo in todos" によって、 { done: false, text: this.addtext }todo として一つひとつ取り出されます。{{todo.text}} で、textの中身が表示されます。

<div class="todo__list" v-for="todo in todos">
 <label class="todo__label">
  <input class="todo__checkbox" type="checkbox" v-model="todo.done">
  <span v-bind:class="{donestyle:todo.done}">{{todo.text}}</span>
 </label>
</div>

todos = [ { done: false, text: "食材を購入する" } ] の場合、配列の中身が一つだけなので、上記HTMLが一度だけ表示されます。{{todo.text}} の部分では、「食材を購入する」が表示されます。

todos = [ { done: false, text: "食材を購入する" }, { done: false, text: "メルカリで出品する" } ] の場合、配列の中身が二つなので、上記HTMLが2回繰り返し表示されます。{{todo.text}} の部分では、1回目は「食材を購入する」、2回目は「メルカリで出品する」が表示されます。

全体の件数を数えて表示させる

{{ todos.length }} では、lengthによってtodosの中身の数を数えて表示させています。

<p>{{ remaining }} / {{ todos.length }}件処理</p>

チェックを入れた後の処理

See the Pen Untitled by Shibata Hiroki (@khiro-enginner) on CodePen.

具体例

チェックを入れる前
チェックを入れた後

食材を購入するというToDoを追加した後に、チェックボックスにチェックを入れると、完了済の見た目になります。また、処理済みの件数が1増えます。

このようにチェックを入れた後の処理について見ていきます。

完了済の見た目になる理由

todo{ done: false, text: this.addtext } というオブジェクトを持っています。

ここで注目すべきなのは、done: false という部分です。

doneというキーは、v-model="todo.done" によってチェックボックスに紐づけられています。そのため、チェックボックスにチェックを入れると、done: true になります。

<input type="checkbox" v-model="todo.done">

v-bind:class="{donestyle:todo.done}" では、テキストのspan要素に donestyle というクラス名をつけるかどうかが決められています。最初は todo done false なので、donestyle が付いていません。チェックボックスにチェックを入れると、donetrue になるので、donestyle が追加されます。

<span v-bind:class="{donestyle:todo.done}">{{todo.text}}</span>

donestyle は、CSSで定義されています。

.donestyle {
  text-decoration: line-through;
  color: lightgray;
}

よって、donestyle が追加されると以下のような完了済の見た目になります。

チェックを入れた後

処理済の件数が1件増える理由

処理済の件数は、{{ remaining }} という部分で表示させています。

<p>{{ remaining }} / {{ todos.length }}件処理</p>

この remaining は、算出プロパティで定義されています。

computed: {
 remaining: function () {
  return this.todos.filter(function (val) {
   return val.done == true;
  }).length;
 }
},

todos done の値が true のオブジェクトを filter でフィルターにかけた後、length で数を取得しています。

チェックボックスにチェックを入れると、donetrue になるので、remaining が返す数が1増えます。

todos = [ { done: false, text: "食材を購入する" } ] の場合、チェックを入れると、todos = [ { done: true, text: "食材を購入する" } ] になり、filter で { done: true, text: "食材を購入する" } が抽出され、その数を length で取得するので、remaining が返す値は1となります。

処理済みToDoを削除する機能

See the Pen Untitled by Shibata Hiroki (@khiro-enginner) on CodePen.

具体例

「食材を購入する」を追加して、チェックを入れた後に、「処理済を削除」をクリックすると、「食材を購入する」が削除され、ToDoの件数が変化します。

「処理済みを削除」をクリックする前
「処理済みを削除」をクリックした後

これについて見ていきます。

処理済みを削除を押したとき

v-on:click="cleanToDo" によって、処理済みを削除をクリックすると、cleanToDo という関数が発火します。

<p><button v-on:click="cleanToDo">処理済みを削除</button></p>

cleanToDo は、以下のように定義されています。todos に対して filter をかけて、donefalse のオブジェクトを抽出して、もう一度 todos に入れ直しています。

methods: {
 cleanToDo: function () {
   this.todos = this.todos.filter(function (val) {
    return val.done == false;
   });
 }
}

todos = [ { done: false, text: "食材を購入する" } ] の場合、チェックを入れると、todos = [ { done: ture, text: "食材を購入する" } ] になります。filter をかけると、donefalse のオブジェクトが存在しないため、todos = [] となります。

ToDoが削除される理由

ToDoは以下のように表示されていました。

<div class="todo__list" v-for="todo in todos">
 <label class="todo__label">
  <input class="todo__checkbox" type="checkbox" v-model="todo.done">
  <span v-bind:class="{donestyle:todo.done}">{{todo.text}}</span>
 </label>
</div>

todos = [] の場合、配列の中身が一つもないので、上記HTMLは表示されません。

ToDoの件数が変化する理由

remaining では残りの件数を、todos.length では全体の件数を表示させていました。

<p>{{ remaining }} / {{ todos.length }}件処理</p>

remaing は以下のように定義されていました。todosdoneture のオブジェクトが1件減るので、remaing が返す値も1減ります。

computed: {
 remaining: function () {
  return this.todos.filter(function (val) {
   return val.done == true;
  }).length;
 }
},

todos = [] の場合、配列の中身が一つもないので、todos.length は0となります。

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です