VueとRailsで作成したアプリで得た知見と備忘録3(ToDoのフロント作成)

2から続いています

目標:処理の流れを忘れた時にすぐに思い出せるようにざっくり解説する。

この章で目指すこと

・AddTodo.vue作成ボタンを押し、$emitを使ってイベント名と共に値を親コンポーネントへ渡す
・親コンポーネントのindex.vue$emitを使って渡ってきた、イベントをトリガーに、methodsと紐づけて、値を子コンポーネントに渡す

・子コンポーネントTodoList.vueで、渡された値をprops登録しておく事で動的な値として扱えるようにする

3章:ToDo機能のページ作成

0:Nuxtの基礎知識(コンポーネント)

Nuxt(Vue.js)のコンポーネントとは?

コンポーネントとは、再利用可能な部品群を指すことが多いです。

Nuxt(Vue.js)におけるコンポーネントは、
再利用可能なVueのインスタンスで、一度作成すれば他の場所で自由に呼び出すことができます。

例えば「ボタンのコンポーネント」を一度作成すれば、
どこのページでも呼び出すことができるようになり
それぞれのページで、毎回ボタンのコードを書く必要がなくなります。
Railsにある部分テンプレートという機能と非常に似ているのがこのコンポーネントです。

0.5:v-タグとVuetifyについて

.vueファイルのコンポーネントでは、<template>というタグの中へ、
コンポーネントとして表示したい内容を書きます。
<v-form>というタグで囲まれたToDo追加のフォームが、
コンポーネントとして表示されます。

例↓

<v-text-field v-model="title" :counter="10" label="todo" required></v-text-field>

v-model="title"とすることで、<script>data()の中で宣言されているtitleとデータを紐づけることができます。

1:AddTodoコンポーネントの作成

frontディレクトリの中に、componentsというディレクトリがあります。
Nuxtのコンポーネントはこのディレクトリの中に作成します。
componentsの中に、AddTodo.vueというファイルを作成し表示したい部分を記述します。

front/components/AddTodo.vue

<template>
 <v-form>
  <v-container>
   <v-row>
    <v-col cols="12" md="4">
     <v-text-field v-model="title" counter="10" label="todo" required></v-text-field>
   </v-col>
    <v-col cols="12" md="4">
      <v-btn @click="handleSubmit">作成</v-btn>
    </v-col>
   </v-row>
  </v-container>
 </v-form>
</template>

<script>
export default {
 data() {
  return {
   title: ""
  };
},
methods: {
  handleSubmit() {
   this.title = "";
  }
 }
};
</script>
<style>
</style>

2:ToDo登録の流れ(↑ので説明)

1:v-model="title"<script>data()の中で宣言されているtitleの値は空なので、
このフォームには初期値として何も入りません。
2:<v-btn @click="handleSubmit">作成</v-btn>
@clickという記法を使って、ボタンをクリックしたとき、
methodsの中で定義した関数を呼び出すことができます。
具体的には、以下の部分が呼び出されます。

methods: {
  handleSubmit() {
  this.title = "";
 },
},

3:ToDoリストコンポーネントの作成

TodoList.vueというファイルを作成します。TodoList.vueに以下の記述を追加します。

<template>
  <v-card>
    <v-card-title>
      Todoリスト
    <v-spacer></v-spacer>
     <v-text-field v-model="search" label="Search" single-line hide-details></v-text-field>
    </v-card-title>
     <v-data-table :headers="headers" :items="todos" :search="search"></v-data-table>
 </v-card>
</template>

<script>
export default {
 data() {
  return {
  todos: [
{
title: "test",
username: "suzutuki"
}
],
search: "",
headers: [
{
  text: "タイトル",
  align: "left",
  sortable: false,
  value: "title"
},
 { text: "ユーザー名", 
 value: "username"
}
]
};
}
};
</script>

<style>
</style>

<v-card>の中にToDoリストのタイトルテーブルを表示しています。

<v-text-field v-model="search" label="Search" single-line hide-details></v-text-field>

v-modelで渡している値は検索バーに入っている初期値です。

a:コロン記法(v-bindの省略)

各プロパティに:(コロン)がたくさんついています。
Vueのv-bindの省略記法で、Vueオブジェクトの変数の値とHTMLを結びつけることができます。
:headersというプロパティにはvueのheadersという変数の値が当てられていますが、
このコロンを消してしまうとエラーが起こります。
vueのオブジェクトが渡されるはずの場所に、”headers”という文字列が渡されてしまうためです。データを渡したいのに、”headers”という文字列が渡されてしまいます。

front/components/TodoList.vue

headers: [
{
 text: "タイトル",
 align: "left",
 value: "title"
},
{ 
 text: "ユーザー名", 
 value: "username" 
}
]

4-1:各プロパティについて(headers)

テーブルのヘッダーとなるプロパティを指定できます。

front/components/TodoList.vue

headers: [
{
text: "タイトル",  // 先頭のヘッダーの内容
align: "left",   // テーブルに対して文字を左寄せ
value: "title"   // どの値をその列に表示させるか
},
{ text: "ユーザー名",
value: "username"
}
]

textには実際にヘッダーの部分に出力させる文字が入りalignは文字の詰め方を指定、
valueは、itemsのプロパティに渡される名前と同様の値が入ります。

※ここを間違えると、値が表示されません(エラーが起こっているようには見えないので注意)。

itemsとして以下のオブジェクトが渡されてきます。

front/components/TodoList.vue

todos: [
{
  title: "test",
  username: "suzutuki"
}
],

titleusernameというプロパティがあります。

titleheadersvalueがtitleの列に、
usernameheadersのvalueがusernameの列へ表示されます。

4-2:各プロパティについて(items)

実際にテーブルへ表示させる値を指定します。
この時、表示させたいプロパティ名を、headersvalueと揃えないとエラーになります!

4-3:各プロパティについて(search)

表示されているToDo(items)をフィルターするときの文字列を指定しています。
v-bindされてsearchという値が指定されています。
これは<v-text-field>で指定されている値です。

front/components/TodoList.vue

<v-text-field v-model="search" label="Search" single-line hide-details></v-text-field>

v-modelsearchという値を指定しています。
このテキストフィールドで入力した値が、searchという値に入り
それがそのまま<v-text-table>searchプロパティの値として利用される訳です。

<v-text-field>に入れた値で、<v-text-table>のToDoをフィルタリングできるという訳です。

5:コンポーネントを表示させるページの作成

index.vueの作成

ページのファイルを作成します。

front/pagesというディレクトリが見つかります。
このディレクトリは、アプリケーションのビューおよび、ルートが格納される場所です。
Nuxtはこのディレクトリ内のすべての .vueファイルを読み込んで、
ルーターの設定を自動的に作成してくれます。

サーバーを立てている状態でhttp://localhost:3000/にアクセスするとindex.vueが表示されます。
これはNuxtで元々の設定で、ルートページに当たるファイルです。

front/pages/index.vueに以下の記述を追加します。

<template>
 <div>
  <AddTodo @submit="addTodo" />
  <TodoList :todos="todos" />
 </div>
</template>

<script>
import AddTodo from "@/components/AddTodo";
import TodoList from "@/components/TodoList";

export default {
 components: {
 AddTodo,
 TodoList,
},
 data() {
  return {
  todos: [],
};
},
methods: {
  addTodo(title) {
   this.todos.push({
    title
  });
 },
},
};
</script>
<style>
</style>

コンポーネントの登録

<script>の中でimportし、importしたコンポーネント
exportの中でcomponentsに登録します。
このように記述することで、<template>の中で作成したコンポーネント
HTMLタグのように使用できます。

@エイリアスと言って、プロジェクトのトップディレクトリを指せる、Nuxtで使える便利な記号
componentsディレクトリの中で作成したAddTodo.vueとTodoList.vueをimportしています。

コンポーネントは、以下のようにタグとして使用しています

front/pages/index.vue

<template>
 <div>
  <AddTodo @submit="addTodo" />
  <TodoList :todos="todos" />
 </div>
</template>

サーバーを立ち上げて表示がおかしくないか確認します。

cd front
npm run dev

http://localhost:3000/

その4に続きます。

6:ToDo登録から表示までの実装

ToDoの追加コンポーネントで作成したToDoを親コンポーネントに伝達してToDoリストコンポーネントに表示

index.vueを親コンポーネントと呼びます。
<AddTodo>コンポーネントと、<TodoList>コンポーネントが、
index.vueに表示されている状態です。
ページの中で、さらにコンポーネントを呼び出しているので、親に当たるのです。

AddTodo.vueから親コンポーネントに登録したいデータを渡す

AddTodo.vue

this.$emit("submit", this.title); // この行を追加します。

↑イベントをトリガーしたいときに使用します。

引数を2つとっており、第一引数のsubmitイベント名、第二引数のthis.titleがイベントとして渡される値になります。
submitというイベント名が親コンポーネントであるindex.vueに渡されます。
親コンポーネント側で「submitと言うイベントが起こったらこの処理を実行する」と言う処理を書いておけば、トリガーになってくれると言う訳です。

7:ToDoの情報を親コンポーネントで受け取って、TodoList.vueに渡す

index.vue

<template>
 <div>
  <!-- divの部分 -->
  <AddTodo @submit="addTodo" /> 
  <TodoList :todos="todos" /> 
 </div>
</template>

@submit=”addTodo”について

v-on:@submit=”addTodo”の省略形です。
AddTodo.vueからsubmitというイベントが来たら、methodsに登録したaddTodo(title)を呼び出します。

リスナーと呼ばれたりします。

このリスナーは、AddTodo.vueを表示するためのコンポーネントに書いてあるので、
AddTodo.vueのイベントを拾ってくれます。

addTodo(title)の引数には自動的にAddTodo.vueで渡したthis.titleが引数として渡されます。

リスナーのコールバック関数に渡されるというのはこれら一連の流れのことです。
$emitを使うだけで、親コンポーネントへ、イベントとコールバックで呼ばれる
メソッドに引数を渡すことができます。

これら一連の動作により、↓の処理が実行されます。

front/pages/index.vue

this.todos.push({
  title
});

data()で宣言されているtodosという配列の中に、AddTodo.vue登録しようとしたToDoの
タイトルが入ります。

最後にそのtodosという値を:todos=”todos”の部分で、TodoList.vue渡しています
=の右側のtodosが、今回渡している値で、左側の:todosは、TodoList.vueで使っている値になります。

8:TodoList.vue内で親コンポーネントから受け取ったTODOを表示させる

front/components/TodoList.vueのscriptの部分を変更します。

<script>
export default {
 props: ["todos"],
 data() {
  return {
  search: "",
// 中略

props: [“todos”]というコードを追加して、todosというプロパティを削除しました。
propsと言うのは、親コンポーネントから子コンポーネントに値を渡す時に使います。

親コンポーネントindex.vueでは:todos=”todos”の部分で、
todosというデータをTodoList.vueに渡していました。
この左側の:todosに当たる部分が、propsに定義しているコードになります。

親から渡してきた値を紐づけることで動的にpropsに登録した値を書き換えています。

親がtodosを更新すると、:todosとpropsにtodosが登録してあることによって、
<v-data-table>の:items=”todos”の部分にて、テーブルのToDoが動的に追加されます。

サーバーを起動して、トップ画面でToDoの値を入れ、送信ボタンを押して
登録できていたらOKです。

その4に続きます

コメントを残す

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