Vue.js2を使用してTo-Doアプリを構築する
序章
Vueは、強力なWebアプリケーションを段階的に構築するために使用できるシンプルで最小限のプログレッシブJavaScriptフレームワークです。
Vueは、AngularJSなどの他のJavaScriptフレームワークの軽量な代替手段です。 HTML、CSS、およびJSの中間的な理解があれば、Vueを起動して実行する準備ができているはずです。
この記事では、Vueが提供する素晴らしいバンドルを強調しながら、Vueを使用してToDoアプリケーションを構築します。
始めましょう!
前提条件
開始するには、VueCLIが必要です。 CLIは、シングルページアプリケーションを迅速にスキャフォールディングする手段を提供し、すぐにアプリをホットリロード、lint-on-save、および本番環境対応のビルドで実行できるようになります。
Vue CLIは、Vueアプリとコンポーネントをジャンプスタートするためのゼロ構成開発ツールを提供します。
将来のアプリの拡張方法に関して行う必要のある多くの決定が処理されます。 Vue CLIには、すぐに使用できる自給自足のパッケージを提供する一連のテンプレートが付属しています。 現在利用可能なテンプレートは次のとおりです。
webpack
-ホットリロード、リンティング、テスト、CSS抽出を備えたフル機能のWebpack+Vueローダーのセットアップ。webpack-simple
-ラピッドプロトタイピングのためのシンプルなWebpack+Vueローダーのセットアップ。browserify
-ホットリロード、リンティング、単体テストを備えたフル機能のBrowserify+vueifyセットアップ。browserify-simple
-ラピッドプロトタイピングのためのシンプルなBrowserify+vueifyセットアップ。simple
-単一のHTMLファイルで可能な限り最も単純なVueセットアップ
簡単に言えば、VueCLIはアプリを起動して実行するための最速の方法です。
# install vue-cli npm install --global vue-cli
このチュートリアルでは、インスタンスではなく単一ファイルコンポーネントの使用に焦点を当てます。 また、親コンポーネントと子コンポーネントの使用方法、およびそれらの間のデータ交換についても触れます。 単一ファイルのコンポーネントを使用する場合、Vueの学習曲線は特に穏やかです。 さらに、コンポーネントに関するすべてを1か所に配置できます。 大規模なアプリケーションで作業を開始すると、再利用可能なコンポーネントを作成できるようになり、命の恩人になります。
Vue2アプリケーションの作成
次に、CLIを使用してVueアプリをセットアップします。
# create a new project using the "webpack" template vue init webpack todo-app
プロジェクト名、説明、作成者、およびVueビルドを入力するように求められます。 アプリにVue-routerをインストールしません。 また、リンティングとテストのオプションまたはアプリを有効にする必要があります。 以下の私の例に従うことができます。
アプリを初期化したら、必要な依存関係をインストールする必要があります。
# install dependencies and go! cd todo-app npm install
アプリを提供するには、次のコマンドを実行します。
npm run dev
これにより、すぐにブラウザが開き、http://localhost:8080
に移動します。 ページは次のようになります。
アプリケーションのスタイルを設定するには、Semanticを使用します。 Semanticは、人間に優しいHTMLを使用して美しく応答性の高いレイアウトを作成するのに役立つ開発フレームワークです。 また、 Sweetalert を使用して、ユーザーにアクションの確認を促します。 Sweetalertは、デフォルトのJavaScriptアラートの美しい代替手段を提供するライブラリです。 縮小されたJavaScriptおよびCSSスクリプトとリンクを、フォルダー構造のルートにあるindex.html
ファイルに追加します。
<!-- ./index.html --> <head> <meta charset="utf-8"> <title>todo-app</title> <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script> <link rel="stylesheet" type="text/css" href="https://cdnjs.cloudflare.com/ajax/libs/semantic-ui/2.2.7/semantic.min.css"> <script src="https://cdnjs.cloudflare.com/ajax/libs/semantic-ui/2.2.7/semantic.min.js"></script> <link rel="stylesheet" type="text/css" href="https://cdnjs.cloudflare.com/ajax/libs/sweetalert/1.1.3/sweetalert.min.css"> <script src="https://cdnjs.cloudflare.com/ajax/libs/sweetalert/1.1.3/sweetalert.min.js"></script> </head>
コンポーネント構造
すべてのVueアプリには、アプリケーション全体のフレームワークとして機能するトップレベルのコンポーネントが必要です。 このアプリケーションでは、メインコンポーネントがあり、その中にネストされているのはTodoList
コンポーネントです。 この中に、Todo
サブコンポーネントがあります。
メインアプリコンポーネント
アプリケーションの構築に飛び込みましょう。 まず、メインのトップレベルコンポーネントから始めます。 Vue CLIは、src/App.vue
にあるメインコンポーネントをすでに生成しています。 その他の必要なコンポーネントを構築します。
コンポーネントの作成
Vue CLIは、セットアップ中にsrc/components/Hello.vue
にあるコンポーネントHello
を作成します。 TodoList.vue
という独自のコンポーネントを作成しますが、これはもう必要ありません。
新しいTodoList.vue
ファイル内に、次のように記述します。
<template> <div> <ul> <li> Todo A </li> <li> Todo B </li> <li> Todo C </li> </ul> </div> </template> <script type="text/javascript"> export default { }; </script> <style> </style>
コンポーネントファイルは3つの部分で構成されています。 テンプレート、コンポーネントクラス、およびスタイルのセクション。
テンプレート領域は、コンポーネントの視覚的な部分です。 テンプレートの動作、イベント、およびデータストレージは、クラスによって処理されます。 スタイルセクションは、テンプレートの外観をさらに改善するのに役立ちます。
コンポーネントのインポート
作成したコンポーネントを利用するには、それをメインコンポーネントにインポートする必要があります。 src/App.vue
内で、スクリプトセクションのすぐ上とテンプレートの終了タグの下に次の変更を加えます。
// add this line import TodoList from './components/TodoList' // remove this line import Hello from './components/Hello'
また、componentsプロパティでTodoList
コンポーネントを参照し、Hello
コンポーネントへの以前の参照を削除する必要があります。 変更後、スクリプトは次のようになります。
<script> import TodoList from './components/TodoList'; export default { components: { // Add a reference to the TodoList component in the components property TodoList, }, }; </script>
コンポーネントをレンダリングするには、HTML要素のようにコンポーネントを呼び出します。 コンポーネントの単語は、キャメルケースの代わりに以下のようにダッシュで区切られます。
<template> <div> // Render the TodoList component // TodoList becomes <todo-list></todo-list> </div> </template>
変更を保存すると、基本的なアプリは次のようになります。
コンポーネントデータの追加
ToDoのリストを表示するために使用される主要コンポーネントにデータを提供する必要があります。 ToDoには3つのプロパティがあります。 title
、project
、およびdone
(ToDoが完了したかどうかを示すため)。 コンポーネントは、data
関数を使用してそれぞれのテンプレートにデータを提供します。 この関数は、テンプレート用のプロパティを持つオブジェクトを返します。 コンポーネントにデータを追加しましょう。
export default { name: 'app', components: { TodoList, }, // data function provides data to the template data() { return { todos: [{ title: 'Todo A', project: 'Project A', done: false, }, { title: 'Todo B', project: 'Project B', done: true, }, { title: 'Todo C', project: 'Project C', done: false, }, { title: 'Todo D', project: 'Project D', done: false, }], }; }, };
メインコンポーネントからTodoList
コンポーネントにデータを渡す必要があります。 このために、v-bind
ディレクティブを使用します。 ディレクティブは、ディレクティブ名の後にコロンで示される引数を取ります。 私たちの引数は、要素のtodos属性を式todosの値にバインドするようにv-bind
ディレクティブに指示するtodosになります。
<todo-list v-bind:todos="todos"></todo-list>
ToDoは、TodoList
コンポーネントでtodos
として使用できるようになります。 このデータにアクセスするには、TodoList
コンポーネントを変更する必要があります。 TodoList
コンポーネントは、使用時に受け入れるプロパティを宣言する必要があります。 これを行うには、コンポーネントクラスにプロパティを追加します。
export default { props: ['todos'], }
データのループとレンダリング
TodoList
テンプレート内で、ToDoのリストをループし、完了したタスクと未完了のタスクの数も表示します。 アイテムのリストをレンダリングするには、v-for
ディレクティブを使用します。 これを行うための構文は、v-for="item in items"
として表されます。ここで、itemsはデータを含む配列であり、itemは繰り返される配列要素の表現です。
<template> <div> // JavaScript expressions in Vue are enclosed in double curly brackets. <p>Completed Tasks: {{todos.filter(todo => {return todo.done === true}).length}}</p> <p>Pending Tasks: {{todos.filter(todo => {return todo.done === false}).length}}</p> <div class='ui centered card' v-for="todo in todos"> <div class='content'> <div class='header'> {{ todo.title }} </div> <div class='meta'> {{ todo.project }} </div> <div class='extra content'> <span class='right floated edit icon'> <i class='edit icon'></i> </span> </div> </div> <div class='ui bottom attached green basic button' v-show="todo.done"> Completed </div> <div class='ui bottom attached red basic button' v-show="!todo.done"> Complete </div> </div> </template> <script type="text/javascript"> export default { props: ['todos'], }; </script>
Todoの編集
よりクリーンなコードのために、todoテンプレートを独自のコンポーネントに抽出してみましょう。 src/components
に新しいコンポーネントファイルTodo.vue
を作成し、todoテンプレートを転送します。 ファイルは次のようになります。
<template> <div class='ui centered card'> <div class='content'> <div class='header'> {{ todo.title }} </div> <div class='meta'> {{ todo.project }} </div> <div class='extra content'> <span class='right floated edit icon'> <i class='edit icon'></i> </span> </div> </div> <div class='ui bottom attached green basic button' v-show="todo.done"> Completed </div> <div class='ui bottom attached red basic button' v-show="!todo.done"> Complete </div> </div> </template> <script type="text/javascript"> export default { props: ['todo'], }; </script>
TodoList
コンポーネントで、コードをリファクタリングしてTodo
コンポーネントをレンダリングします。 また、todoがTodo
コンポーネントに渡される方法を変更する必要があります。 v-for
属性は、他の要素と同じように、作成するすべてのコンポーネントで使用できます。 構文は次のようになります:<my-component v-for="item in items" :key="item.id"></my-component>
。
2.2.0以降では、コンポーネントでv-for
を使用する場合、key
が必要になることに注意してください。
注意すべき重要な点は、コンポーネントには独自の分離されたスコープがあるため、これによってデータがコンポーネントに自動的に渡されないことです。 データを渡すには、小道具を使用する必要があります。
<my-component v-for="(item, index) in items" v-bind:item="item" v-bind:index="index"> </my-component>
リファクタリングされたTodoList
コンポーネントテンプレート:
<template> <div> <p>Completed Tasks: {{todos.filter(todo => {return todo.done === true}).length}}</p> <p>Pending Tasks: {{todos.filter(todo => {return todo.done === false}).length}}</p> // we are now passing the data to the todo component to render the todo list <todo v-for="todo in todos" v-bind:todo="todo"></todo> </div> </template> <script type = "text/javascript" > import Todo from './Todo'; export default { props: ['todos'], components: { Todo, }, }; </script>
isEditing
というプロパティをTodo
コンポーネントクラスに追加しましょう。 これは、Todo
が編集モードであるかどうかを判別するために使用されます。 テンプレートの編集スパンにイベントハンドラーがあります。 これにより、クリックされたときにshowForm
メソッドがトリガーされます。 これにより、isEditing
プロパティがtrueに設定されます。 それを見る前に、フォームを追加し、isEditing
プロパティがtrue
またはfalse
のどちらであるかに応じて、ToDoまたは編集フォームを表示する条件を設定します。 テンプレートは次のようになります。
<template> <div class='ui centered card'> // Todo shown when we are not in editing mode. <div class="content" v-show="!isEditing"> <div class='header'> {{ todo.title }} </div> <div class='meta'> {{ todo.project }} </div> <div class='extra content'> <span class='right floated edit icon' v-on:click="showForm"> <i class='edit icon'></i> </span> </div> </div> // form is visible when we are in editing mode <div class="content" v-show="isEditing"> <div class='ui form'> <div class='field'> <label>Title</label> <input type='text' v-model="todo.title" /> </div> <div class='field'> <label>Project</label> <input type='text' v-model="todo.project" /> </div> <div class='ui two button attached buttons'> <button class='ui basic blue button' v-on:click="hideForm"> Close X </button> </div> </div> </div> <div class='ui bottom attached green basic button' v-show="!isEditing &&todo.done" disabled> Completed </div> <div class='ui bottom attached red basic button' v-show="!isEditing && !todo.done"> Pending </div> </div> </template>
showForm
メソッドに加えて、hideForm
メソッドを追加して、キャンセルボタンがクリックされたときにフォームを閉じる必要があります。 スクリプトがどのようになるか見てみましょう。
<script> export default { props: ['todo'], data() { return { isEditing: false, }; }, methods: { showForm() { this.isEditing = true; }, hideForm() { this.isEditing = false; }, }, }; </script>
フォームの値をtodo値にバインドしたので、値を編集するとすぐにtodoが編集されます。 完了したら、閉じるボタンを押して、更新されたToDoを確認します。
Todoの削除
編集アイコンのすぐ下にあるTodo
を削除するアイコンを追加することから始めましょう。
<template> <span class='right floated edit icon' v-on:click="showForm"> <i class='edit icon'></i> </span> /* add the trash icon in below the edit icon in the template */ <span class='right floated trash icon' v-on:click="deleteTodo(todo)"> <i class='trash icon'></i> </span> </template>
次に、アイコンのクリックを処理するメソッドをコンポーネントクラスに追加します。 このメソッドは、イベントdelete-todo
を親TodoList
コンポーネントに発行し、現在のTodo
を渡して削除します。 削除アイコンにイベントリスナーを追加します。
<span class='right floated trash icon' v-on:click="deleteTodo(todo)">
// Todo component methods: { deleteTodo(todo) { this.$emit('delete-todo', todo); }, },
親コンポーネント(TodoList
)には、削除を処理するためのイベントハンドラーが必要です。 それを定義しましょう。
// TodoList component methods: { deleteTodo(todo) { const todoIndex = this.todos.indexOf(todo); this.todos.splice(todoIndex, 1); }, },
deleteTodo
メソッドは、次のようにTodoコンポーネントに渡されます。
// TodoList template <todo v-on:delete-todo="deleteTodo" v-for="todo in todos" v-bind:todo="todo"></todo>\
削除アイコンをクリックすると、イベントが発行されて親コンポーネントに伝播され、親コンポーネントが削除します。
新しいTodoを追加する
新しいtodoを作成するには、src/components
に新しいコンポーネントCreateTodoを作成することから始めます。 これにより、クリックするとフォームに変わるプラス記号の付いたボタンが表示されます。 このように見えるはずです。
<template> <div class='ui basic content center aligned segment'> <button class='ui basic button icon' v-on:click="openForm" v-show="!isCreating"> <i class='plus icon'></i> </button> <div class='ui centered card' v-show="isCreating"> <div class='content'> <div class='ui form'> <div class='field'> <label>Title</label> <input v-model="titleText" type='text' ref='title' defaultValue="" /> </div> <div class='field'> <label>Project</label> <input type='text' ref='project' defaultValue="" /> </div> <div class='ui two button attached buttons'> <button class='ui basic blue button' v-on:click="sendForm()"> Create </button> <button class='ui basic red button' v-on:click="closeForm"> Cancel </button> </div> </div> </div> </div> </div> </template> <script> export default { data() { return { titleText: '', projectText: '', isCreating: false, }; }, methods: { openForm() { this.isCreating = true; }, closeForm() { this.isCreating = false; }, sendForm() { if (this.titleText.length > 0 && this.projectText.length > 0) { const title = this.titleText; const project = this.projectText; this.$emit('create-todo', { title, project, done: false, }); this.newTodoText = ''; } this.isCreating = false; }, }, }; </script>
新しいコンポーネントを作成したら、それをインポートして、コンポーネントクラスのcomponentsプロパティに追加します。
// Main Component App.vue components: { TodoList, CreateTodo, },
また、新しいToDoを作成するためのメソッドを追加します。
// App.vue methods: { addTodo(title) { this.todos.push({ title, done: false, }); }, },
CreateTodoコンポーネントは、App.vueテンプレートで次のように呼び出されます。
<create-todo v-on:add-todo="addTodo">
Todoを完了する
最後に、メソッドcompleteTodo
をTodo
コンポーネントに追加します。このメソッドは、保留中のボタンがクリックされたときにイベントcomplete-todo
を親コンポーネントに発行し、完了ステータスを設定します。 todo
からtrue
。
// Todo component methods: { completeTodo(todo) { this.$emit('complete-todo', todo); }, }
イベントハンドラーがTodoList
コンポーネントに追加され、イベントが処理されます。
methods: { completeTodo(todo) { const todoIndex = this.todos.indexOf(todo); this.todos[todoIndex].done = true; }, },
TodoList
メソッドをTodo
コンポーネントに渡すために、Todo
コンポーネントの呼び出しに追加します。
<todo v-on:delete-todo="deleteTodo" v-on:complete-todo="completeTodo" v-for="todo in todos" :todo.sync="todo"></todo>
結論
VueCLIを使用してVueアプリを初期化する方法を学びました。 さらに、コンポーネントの構造、コンポーネントへのデータの追加、イベントリスナー、およびイベントハンドラーについて学習しました。 ToDoを作成し、編集し、削除する方法を見ました。 学ぶべきことはまだたくさんあります。 主要コンポーネントでは静的データを使用しました。 次のステップは、サーバーからデータを取得し、それに応じて更新することです。 これで、インタラクティブなVueアプリケーションを作成する準備が整いました。 自分で何か他のことを試して、それがどうなるかを見てください。 乾杯!