Vue 公式チュートリアル 〜 処理したデータを表示に使う

記事
IT・テクノロジー

Vue 公式チュートリアル 〜 処理したデータを表示に使う

Vue 公式チュートリアルのステップ8は、予め処理したデータを表示に使う方法を学習します。Javascript のプログラムで持っているデータは、「生」のデータの場合が多く、実際の表示をする際には、そのデータを「加工」して利用したい場合が、たくさんあります。そうした場合の処理の仕方を学習します。

前回までのポイントは?

一通り、Vue の「部品」の基本的な、書き方がわかったところで、前回のステップ7からは、プログラミング的な要素が増えてきました。前回の、チュートリアルのタイトルは、「データの一覧表示」がテーマでしたが、実際は、HTML や Javascript で新しい部分がたくさん出てきました。

* 配列(array)という同じ形のデータをまとめて扱うためのデータの型が出てきました。
* 「@keyup.enter」は、リターンキーが押された場合の処理を HTML の部分に書くやり方です。
* 「v-for」は、配列(array)のデータの一覧を表示するための、繰り返しなるような表示の HTML の書き方です。
* 処理を行うメソッド(関数)に値を渡すやり方も出てきました。
「filter()」というメソッド(関数)を使うと、配列(array)の要素を選ぶことができます。
* 「++」という「1を加える」という演算子が出てきました。
* HTML の記述で「箇条書き」を行うやり方が出てきました。(「ul」と「li」のタグ)
と実際の内容では、新しく学習した項目が多いステップでした。この他にも、以前のステップで出てきた書き方が使われていたので、何回か、前のステップを実際にやってみて、そうした項目が使えるようになっているかを確認してください。

今回学ぶのは?

今回のステップ8では、引き続き前回と同じ「やる事リスト」を管理するアプリの続編です。 前回のステップ7では、やる事を「削除」する機能はありました。従って、やる事が完了した項目は削除してしまえば、まだ終わっていない項目だけを表示できるので、やる事を管理する事ができました。しかし、「やった事を後で見たい場合」には、やった事を削除してしまうと見る事はできません。「成果」が確認できるようにして、本当に表示させる必要がなくなった時点で削除するという形に変更するというのが今回の課題です。

まずは、変更前のコードです。

<script>
let id = 0;

export default {
  data() {
    return {
      newTodo: "",
      hideCompleted: false,
      todos: [
        { id: id++, text: "Learn HTML", done: true },
        { id: id++, text: "Learn JavaScript", done: true },
        { id: id++, text: "Learn Vue", done: false },
      ],
    };
  },
  computed: {
    // ...
  },
  methods: {
    addTodo() {
      this.todos.push({ id: id++, text: this.newTodo, done: false });
      this.newTodo = "";
    },
    removeTodo(todo) {
      this.todos = this.todos.filter((t) => t !== todo);
    },
  },
};
</script>

<template>
  <input v-model="newTodo" @keyup.enter="addTodo" />
  <button @click="addTodo">Add Todo</button>
  <ul>
    <li v-for="todo in todos" :key="todo.id">
      <input type="checkbox" v-model="todo.done" />
      <span :class="{ done: todo.done }">{{ todo.text }}</span>
      <button @click="removeTodo(todo)">X</button>
    </li>
  </ul>
  <button @click="hideCompleted = !hideCompleted">
{{ hideCompleted ? "Show all" : "Hide completed" }}
  </button>
</template>

<style>
.done {
  text-decoration: line-through;
}
</style>
基本は、前回のコードですが、何点か既に変更されています

* やる事のデータに「done」というタグが追加されています
* やる事の表示の仕方が変更されています。
* 新しく「hideCompleted」(終わった事を隠す)というボタンが追加されています。
* 「style」のタグ(CSS の記述)が追加されています
「done」はやる事が「終わっているかどうか」の状態を示す変数です。この値を使って表示を変えています。 表示の部分は

<li v-for="todo in todos" :key="todo.id">
  <input type="checkbox" v-model="todo.done" />
  <span :class="{ done: todo.done }">{{ todo.text }}</span>
  <button @click="removeTodo(todo)">X</button>
</li>
のようになっていて、

<input type="checkbox" v-model="todo.done" />
が追加されています。「チェックボックス」という表示のための部品で、クリックしてチェックすることで、その「やる事」が終わっているかどうかを選べるようになっています。「v-model」を使って、チェックされているかどうかの状態を「todo.done」という新しく Javascript 側で追加した変数と結びつけて状態を管理しています。

その次の行は、

<span :class="{ done: todo.done }">{{ todo.text }}</span>
が追加されていて、「:class」の部分に、「"{ done: todo.done }"」が書かれていて、「done」というタグで CSS の記述で「飾り」ができるようになっています。この記述は、HTML の「span」というタグで囲まれていて、この記述は、このタグで囲んだ範囲の文字に「飾り」をつけるための記述です。文字列の特定の部分の色を変えたりしたい場合に使われます。 「:class」はこれまでにも、「style」で書かれている CSS の記述と結びつけるために以前のステップでも使われています。今回は、これに「{ done: todo.done}」とすることで、「todo.done」の状態によって、このタグを有効にするかどうかを決めています。「todo.done」が「true」の場合は、「タグが有効」になります。逆に、「todo.done」が「false」の場合は、「タグは無効」になります。

「style」のタグに書かれた CSS は次のようになっています。

.done {
  text-decoration: line-through;
}
これは、文字の飾り(text-decoration)で、「line-through」つまり、横線で消した表示になるようにしています。

まとめると、「todo.done」が「true」の場合は、この記述が有効になって「横線で消された表示」になって、「todo.done」が「false」の場合は、「:class」のタグが無効になるので、この CSS の記述は無視されるので「普通に表示」されることになります。

追加されたボタン

<button @click="hideCompleted = !hideCompleted">
{{ hideCompleted ? 'Show all' : 'Hide completed' }}
</button>
は表示モードを切り替えるためのボタンになります。 ここでは二つの新しい書き方が出てきています。 最初が、ボタンがクリックされた場合の処理を記述する「@click」の部分です。これまでは、処理を行うメソッド(関数)を呼び出す書き方でしたが、このステップでは、直接処理の内容「hideCompleted = !hideCompleted」を書いています。このようにシンプルな処理の場合は直接、Javascript のプログラムをここに書く事ができます。 もう一つは、「{{ hideCompleted ? 'Show all' : 'Hide completed' }}」です。この部分はボタンに表示される文字を指定している部分ですが、Javascript で作った変数「hideComplted」の値によって表示する文字を変えるような記述になっています。これも、Javascript の記述なのですが、「hideCompleted」が「true」の場合は、最初に書かれている「Show all」が表示されます。逆に、「hideCompleted」が「false」の場合には、二番目に書かれている「Hide completed」が表示されるようになっています。 「条件 ? true の場合の表示内容 : false の場合の表示内容」という形です。今回は、文字列の選択に使われていますが、条件によって「値」を選ぶための Javascript の記述です。

ボタンをクリックすることで、「hideCompleted」の値が変わるので、このボタンをクリックすることで表示内容を変えるのに使われています。

このように、Vue では HTML の部分の記述に Javascript の記述を埋め込んで書くこともできます。

さて、本題のこのステップの課題ですが、一覧の表示の際に、「hideCompleted」の状態によって表示する内容を変えるように記述を変更するのが課題です。HTML の部分の記述と、Javascript 部分の記述の変更が必要になります。

変更後のコードは?

変更後のコードは次のようになっています。

<script>
let id = 0;

export default {
  data() {
    return {
      newTodo: "",
      hideCompleted: false,
      todos: [
        { id: id++, text: "Learn HTML", done: true },
        { id: id++, text: "Learn JavaScript", done: true },
        { id: id++, text: "Learn Vue", done: false },
      ],
    };
  },
  computed: {
    filteredTodos() {
      return this.hideCompleted
        ? this.todos.filter((t) => !t.done)
        : this.todos;
    },
  },
  methods: {
    addTodo() {
      this.todos.push({ id: id++, text: this.newTodo, done: false });
      this.newTodo = "";
    },
    removeTodo(todo) {
      this.todos = this.todos.filter((t) => t !== todo);
    },
  },
};
</script>

<template>
  <input v-model="newTodo" @keyup.enter="addTodo" />
  <button @click="addTodo">Add Todo</button>
  <ul>
    <li v-for="todo in filteredTodos" :key="todo.id">
      <input type="checkbox" v-model="todo.done" />
      <span :class="{ done: todo.done }">{{ todo.text }}</span>
      <button @click="removeTodo(todo)">X</button>
    </li>
  </ul>
  <button @click="hideCompleted = !hideCompleted">
{{ hideCompleted ? "Show all" : "Hide completed" }}
  </button>
</template>

<style>
.done {
  text-decoration: line-through;
}
</style>
変更箇所は二つです

* Javascript の「computed:{}」の部分の追加
* HTML の一覧の表示の変更
Javascript で処理を行う場合は、「methods:{}」の中にメソッド(関数)を記述していました。今回は、これの代わりに「computed:{}」の中にメソッド(関数)を記述します。

違いは、状態によって表示する内容を変えたい場合、今回の場合は、「hideComplted」の値によって表示する内容が違っています。このような場合、「hideCompleted」が変化した場合に、表示内容を書き換える必要があります。「computed」を使うと、Vue が「hideCompleted」の状態を見ていて、書き変わると表示データを更新してくれます。

今回のステップでは以下の処理「filterdTodos()」を「computed:{}」に追加します。

computed: {
    filteredTodos() {
      return this.hideCompleted
        ? this.todos.filter((t) => !t.done)
        : this.todos
    }
},
ここでも、前回出てきた、「filter()」を使って表示する項目を選んでいます。ここでも、変更前のコードでも使われている「状態 ? 状態が true の場合 : 状態が false の場合」が使われています。

「this.hideCompleted」が「true」の場合は、「filter」を使って、やる事「t」のタグ「done」の値が「true でない(false)」を抜き出すようになっています。それ以外(this.hideCompleted が false)の場合は、「this.todos」をそのまま使うようになっています。

HTML の表示の方も、この「filterTodos()」の処理結果を使うように変更されています。

<li v-for="todo in filteredTodos" :key="todo.id">
  <input type="checkbox" v-model="todo.done" />
  <span :class="{ done: todo.done }">{{ todo.text }}</span>
  <button @click="removeTodo(todo)">X</button>
</li>

「v-for」の「in todos」の部分が「filteredTodos」で「computed:{filterTodos()}」の値を使うように変更されています。つまり、予め処理したデータを表示に使うという意味で、「hideCompleted」の値によって表示内容が反映されるようになっています。

今回の応用は?

今回の応用は、「filterdTodos()」の処理を「methods:{}」の中に書いてみて、結果がどのようになるかを体験してください。この実験をする事で、「methods:{}」と「computed:{}」の違いが体験できるので、何故、このステップでは「computed:{}」の中に記述しなければいけないかがハッキリします。

具体的なコードはこんな感じになります

<script>
let id = 0;

export default {
  data() {
    return {
      newTodo: "",
      hideCompleted: false,
      todos: [
        { id: id++, text: "Learn HTML", done: true },
        { id: id++, text: "Learn JavaScript", done: true },
        { id: id++, text: "Learn Vue", done: false },
      ],
    };
  },
  computed: {},
  methods: {
    addTodo() {
      this.todos.push({ id: id++, text: this.newTodo, done: false });
      this.newTodo = "";
    },
    removeTodo(todo) {
      this.todos = this.todos.filter((t) => t !== todo);
    },
    filteredTodos() {
      return this.hideCompleted
        ? this.todos.filter((t) => !t.done)
        : this.todos;
    },
  },
};
</script>

<template>
  <input v-model="newTodo" @keyup.enter="addTodo" />
  <button @click="addTodo">Add Todo</button>
  <ul>
    <li v-for="todo in filteredTodos" :key="todo.id">
      <input type="checkbox" v-model="todo.done" />
      <span :class="{ done: todo.done }">{{ todo.text }}</span>
      <button @click="removeTodo(todo)">X</button>
    </li>
  </ul>
  <button @click="hideCompleted = !hideCompleted">
{{ hideCompleted ? "Show all" : "Hide completed" }}
  </button>
</template>

<style>
.done {
  text-decoration: line-through;
}
</style>
どうですか、やる事の一覧が表示されなくなってしまいますよね!?

簡単にいうと、「computed」に書かれたメソッド(関数)は、表示データの「前処理」を Javascript の変数の状態によって行うものです。「methods」に書かれたメソッドは「きっかけ」がないと呼び出されない処理になります。つまり、クリックされたなどのイベントが起きるなど、「きっかけ」が必要になります。この変更例では「filteredTodos()」を呼び出す「きっかけ」がないので何も表示されません。ただ、HTML の記述に書いただけでは、Javascript の「methods」に書かれた処理は呼び出されないという事です。

表示に処理結果を使いたい場合には、「computed」に書く必要があります。

まとめ

このステップでも新い学習内容がたくさん出てきました。

もう一度復習してみてください。

* 簡単な Javascript の処理は、HTML の部分にも埋め込める
* 「状態(条件) ? true の場合 : false の場合」の書き方
* 状態(条件)による「:class」の有効化・無効化
* 「computed」の使い方
特に、「methods」と「computed」のメソッド(関数)の違いは、応用編で体験した様に表示に影響が出ます。違いをよく理解して、上手く使いこなせるようになることがこのステップのポイントです。Web アプリでは条件によって、データを処理して表示に使う場合はたくさんあるので、この違いをきちんと理解していることはとても大切なポイントです。

次回は 2022 年 3 月 2 日の水曜日にお届けします。
サービス数40万件のスキルマーケット、あなたにぴったりのサービスを探す