LoginSignup
2
1

More than 3 years have passed since last update.

【Vue.js】簡単なToDoアプリの制作と学習メモ

Last updated at Posted at 2021-04-11

きっかけ

これまでVueを用いてアプリを作ったりしていたのですが,Vueについての基本的なことが全然理解できていなかったことやFirebaseでサイトを公開してみたかったため学習を兼ねて作ってみました.

完成物

ToDoアプリ

image.png

構成

"Index.vue(src/pages/Index.vue)"という大枠のページの中に,

  • Todoを書きこむ"TodoForm.vue(src/components/TodoForm.vue)"
  • 書き込んだTodoを表示させる"TodoList.vue(src/components/TodoList.vue)"

の2つのコンポーネントを組み込んだ形になります.

スタイルはBootstrap-Vueを使いました.

インポート

Bootstrapの公式サイトに従ってコマンドを打ち込みます.

npm install vue bootstrap bootstrap-vue

次にindex.js内でimport

index.js
import Vue from 'vue'
import Router from 'vue-router'
import Index from '@/pages/Index'
import { BootstrapVue, IconsPlugin } from 'bootstrap-vue'
// Import Bootstrap an BootstrapVue CSS files (order is important)
import 'bootstrap/dist/css/bootstrap.css'
import 'bootstrap-vue/dist/bootstrap-vue.css'

// Make BootstrapVue available throughout your project
Vue.use(BootstrapVue)
// Optionally install the BootstrapVue icon components plugin
Vue.use(IconsPlugin)

Vue.use(Router)

export default new Router({
  routes: [
    {
      path: '/',
      name: 'Index',
      component: Index
    }
  ]
})

Index.vue

大枠となるページのファイル

Index.vue
<template>
  <div>
    <h1>ToDoリスト</h1>
    <todo-form @handleParentAddTodo="handleParentAddTodo" />
    <todo-list
      :todos="todos"
      @handleParentDeleteTodo="handleParentDeleteTodo"
      @handleParentCompleteTodo="handleParentCompleteTodo" />
  </div>
</template>

<script>
// TodoForm,TodoList読み込み
import TodoForm from '@/components/TodoForm'
import TodoList from '@/components/TodoList'

export default {
  name: 'Todo',
  components: {
    TodoForm,
    TodoList
  },
  data () {
    return {
      // データバインディング
      todos: []
    }
  },
  methods: {
    // v-onでメソッド呼び出し
    // Todoリスト追加処理
    handleParentAddTodo (value) {
      if (value) {
        this.todos.unshift({ text: value, complete: false })
      }
    },
    // Todoリスト完了処理
    // この処理でcompleteの真偽を逆転させる
    handleParentCompleteTodo (index) {
      this.todos[index].complete = !this.todos[index].complete
    },
    // Todoリスト削除処理
    // spliceで引数の一行を消去
    handleParentDeleteTodo (index) {
      this.todos.splice(index, 1)
    }
  }
}
</script>

<style>

</style>

TodoForm.vue

Todoリストを書き込み送信するファイル

handleAddTodo関数の$emitで子コンポーネント(TodoForm.vue)から親コンポーネント(Index.vue)へイベントを放っている

TodoForm.vue
<template>
  <b-container>
    <b-input-group>
      <!-- v-model属性で双方向ディバイディング -->
      <b-form-input type="text" v-model="value"/>
      <b-input-group-append>
        <b-button variant="primary" @click="handleAddTodo()">送信</b-button>
      </b-input-group-append>
    </b-input-group>
  </b-container>
</template>

<script>
export default {
  name: 'TodoForm',
  data () {
    return {
      value: ''
    }
  },
  methods: {
    // 送信ボタンクリック時に処理される関数
    handleAddTodo () {
      // Index.vueのhandleParentAddTodoにフォーム内の値を引数に発火
      this.$emit('handleParentAddTodo', this.value)
      this.value = ''
    }
  }

}
</script>

<style>

</style>

TodoList.vue

フォームで送信されたTodoリストを表示したり,進捗を操作するファイル

TodoFormと同様にhandleCompleteTodo関数,handleDeleteTodo関数の$emitで子コンポーネント(TodoList.vue)から親コンポーネント(Index.vue)へイベントを放っている

TodoList.vue
<template>
  <b-container>
    <!-- for文でTodoリストをひとつづつ処理 -->
    <b-row :key="index" v-for="(todo, index) in todos" class="mt-2">
      <!-- v-bindのclass属性によりcomplete時にstyleが適用 -->
      <b-col cols="8" :class="[{line: todo.complete}, 'text-left']">
        <h5>{{todo.text}}</h5>
      </b-col>
      <b-col cols="4" class="text-right">
        <b-button @click="handleCompleteTodo(index)"
        :variant="todo.complete ? '' : 'success'">
          {{ todo.complete ? '完了' : '未完了'}}
          </b-button>
        <b-button @click="handleDeleteTodo(index)" variant="danger">削除</b-button>
      </b-col>
    </b-row>
  </b-container>
</template>

<script>
export default {
  name: 'TodoList',
  // 親コンポーネントからv-bindで渡された値(todos)を受け取る
  props: ['todos'],
  methods: {
    // 完了ボタンクリック時に処理される関数
    handleCompleteTodo (index) {
      // Index.vueのhandleParentCompleteTodoにフォーム内の値を引数に発火
      this.$emit('handleParentCompleteTodo', index)
    },
    // 削除ボタンクリック時に処理される関数
    handleDeleteTodo (index) {
      // Index.vueのhandleParentDeleteTodoにフォーム内の値を引数に発火
      this.$emit('handleParentDeleteTodo', index)
    }
  }
}
</script>

<style scoped>
  .line {
    text-decoration: line-through;
  }
</style>

FirebaseでHosting

以下の記事を参考にさせていただきました

まとめ

Todoアプリの制作を通して,v-model,v-bind,v-onについて一通りさわることができた.

propsと$emitという親コンポーネントと子コンポーネントをつなぐ概念について理解できた.

Firebaseで簡単にサイト公開をすることができた.

2
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
1