ともすたmedia
この記事は、「これからはじめる人のJavaScript/Vue.jsの教科書」のVue3対応、アップデート記事です。本書をお持ちの方は、後半の記事を以下の記事に差し替えてご利用ください。
Vue.jsは、JavaScriptと組み合わせて利用できる「フレームワーク」の1つで、簡単な手続きで本格的なウェブアプリを構築できるのが特徴です。
現在でも活発に開発されていて、2020年には最新のVue 3がリリースされました。
ここでは、そんなVue 3を利用し、複数ページを制御できるVue Router、データの管理を行うVuexと、ローカルストレージにデータを保存できるvuex-persistを利用した、メモ帳アプリの開発を紹介しましょう。
Vue CLI/Vue UIを利用しよう
Vueには、コマンドラインでVueのさまざまな操作を行える「Vue CLI(Command Line Interface)」と、そのVue CLIをブラウザー上で操作できる「Vue UI(User Interface)」というツールが提供されています。
まずはこれをインストールしておきましょう。なお、この操作には「Node.js」の「npm」というツールが必要です。もし、まだインストールしていない場合や、次のコマンドを入力した時に「Command Not Found(コマンドが見つかりません)」などのエラーメッセージが表示された場合は、次のサイトからプログラムをダウンロードして、先にNode.jsとnpmをインストールしておきましょう。
node -v
Node.jsやnpmについて詳しくは、次の記事もご参照ください。
Vue CLIをインストールしよう
それでは、Vue CLIをインストールしましょう。macOSの場合はFinderから「アプリケーション→ユーティリティ→ターミナル」を起動します。Windowsの場合は、スタートボタンを右クリックして「Microsoft Terminal」を起動しましょう。そしたら、次のようにコマンドを入力します。
npm i -g @vue/cli
これでVue CLIがインストールされました。続けて、次のようにコマンドを入力してインストールされているかを確認しましょう。
vue -version
図のように表示されていれば、利用できます。
Vue UIを起動しよう
それでは、Vueのプロジェクトを管理する「Vue UI」を起動してみましょう。次のようにコマンドを入力します。
vue ui
ウェブブラウザーが起動して、図のような画面が表示されます。
もし画面が違う場合は、図のボタンでホームに戻っておきましょう。
新しいプロジェクトを作成しよう
ここでは、Vueのプロジェクトを作成できます。Vue自身は既存のHTMLファイルに後から組み込んで利用する事もできる、非常に手軽なフレームワークです。
しかし、その場合はこの後紹介する「コンポーネント」を作成するフォルダーの名前をなににするかなどのルールを自分で決めなければなりません。それでは、チームで開発する時などにルールを統一するのに手間がかかってしまうでしょう。
そこで、Vueでは標準としてフォルダー名の命名規則やファイル名の命名規則などを定め、それに沿った基本ファイル群を一気に生成してくれるビルドツールが提供されています。これをブラウザー上から利用できるのが「Vue UI」なのです。
では、ホームに戻ったら、図の「作成」ボタンをクリックしましょう。
プロジェクトを作成したいフォルダーを選んで、画面下の「ここに新しいプロジェクトを作成する」ボタンをクリックしましょう。
「プロジェクトフォルダ」にプロジェクトを作成するフォルダー名を入力します。
パッケージマネージャーはデフォルトの「npm」を利用していきます。これは、この後登場する「サーバー」を利用したりする際の管理ツールを指定するものです。ここでは、この記事の冒頭でインストールした「Node.js」の「npm」を引き続き利用します。他にyarnやpnpmなどが利用できますがここでは説明を省略します。
追加オプションはOFFのままで良いでしょう。「Gitリポジトリ」は、「バージョン管理システム」の利用の有無になります。ここでは説明を省略するので、知らないという方はOFFにしておくと良いでしょう。「次へ」をクリックします。
次に、Vueのバージョンなどを選ぶことができます。ここでは、「Default (Vue 3)」を選びましょう。「プロジェクトを作成する」ボタンをクリックします。
しばらく待つと、図のようなプロジェクトダッシュボードが起動します。これで準備完了です。
サーバーを起動しよう
Vue CLI(Vue UI)で作成したプロジェクトには、簡易的なサーバー機能が搭載されています。開発中は、常にこのサーバーを起動した状態で行って行きます。
それでは、図のボタンをクリックしてタスクの中から「serve」を選びましょう。
「タスクの実行」ボタンをクリックすると、サーバーが起動して図のような画面になります。もしここで、エラーなどが表示された場合は、他のサーバーが起動していないかなどを確認して、コンピューターを再起動するなどしてみてください。
正常に起動したら、図の「アプリを開く」ボタンをクリックしましょう。
図のような画面が表示されれば、サンプルで作成されたアプリが起動しています。
ファイルの構成を確認しよう
それでは、ここで作られたプロジェクトフォルダーの内容を確認していきましょう。Visual Studio Codeなどの開発エディターを利用すると便利でしょう。
node_modules
ここにVueの本体や、この後インストールするプラグインの本体ファイルなどが格納されます。このフォルダーを手で操作することはあまりありません。
public
ウェブサーバーが最初に確認するフォルダーです。この中には「index.html」が含まれていて、次のような内容が記述されています。
<noscript>
<strong>We're sorry but <%= htmlWebpackPlugin.options.title %> doesn't work properly without JavaScript enabled. Please enable it to continue.</strong>
</noscript>
<div id="app"></div>
<!-- built files will be auto injected -->
JavaScriptが動作しない環境で起動した時に表示されるメッセージと、<div id="app"></div>
というdiv要素だけがありますが、この「app」というid属性が後で重要な意味を持ちます。ここに、実際のプログラムの内容が表示されます。
もう1つ作られている「favicon.ico」は、ブラウザーのタブに表示されるアイコンです。実際に自分で利用するアイコンに差し替えるか、なければ削除してしまって良いでしょう。その場合は、「index.html」の次の記述も削除しておきましょう。
<link rel="icon" href="<%= BASE_URL %>favicon.ico">
src
このフォルダーが、普段開発する時に作業するフォルダーになります。標準ではApp.vue
とmain.js
というファイルが含まれています。これについては、この後紹介していきます。さらに、サブフォルダーがいくつかあります。
src/assets
プロジェクト内で利用する画像ファイルや、CSSファイルなどを配置するフォルダーです。標準では、logo.png
という画像ファイルが入っていますが、これは不要なので削除しておきましょう。
src/components
「コンポーネント」と呼ばれる、共通パーツを入れるフォルダーです。標準ではサンプルのHelloWorld.vue
というファイルが配置されていますが、これは不要なので削除しておきます。
その他、次のファイルが配置されています。
・.gitignore: Gitで「無視」をするファイルのリスト
・babel.config.js: Babelというビルドツールで利用する設定ファイル
・jsconfig.json: ビルドツールのJavaScriptビルドの設定
・package.json: npmのパッケージを設定するファイル
・README.md: プロジェクトのドキュメントなどを記載するファイル
・vue.config.js: Vueの設定ファイル
・yarn.lock: Yarnというツールの設定ファイル
いずれも特に編集などは必要ないので、このままにしておきましょう。
この状態で、先ほど起動したウェブブラウザーに戻ってみましょう。画面が図のように英文のメッセージだらけになってしまいました。
これは、先ほどいくつかの不要ファイルを削除したため、ファイルのリンクが途切れてしまったエラーが表示されています。
src/App.vue
ファイルをエディターで開いて、このファイルの内容を空にしてしまいましょう。これでブラウザーに戻れば、エラーメッセージは消えて、真っ白の画面になりました。ここから開発をスタートすることができます。
vue-routerをインストールしよう
ウェブサイトを見ていると、見ているページによって、アドレスが次のように変化することがあります。
https://example.com/
↓
https://example.com/new
サーバーは、このようなアドレスを確認して、どのような情報をウェブブラウザーに渡すかというのを判断しています。これを「ルーティング」といい、Vueではこのようなルーティングを行うためのプラグインが提供されていて、簡単に実装できます。
ここでは「Vue Router」をインストールしてみましょう。Vueでは、プラグインのインストールなどもVue UI上で行えます。
Vue UIを起動して、「プロジェクトダッシュボード」にアクセスしましょう。
「プラグイン」ボタンをクリックすると、今インストールされているプラグインが一覧されます。
ここで新しいプラグインを追加します。Vue Routerは、よく利用されるため画面上部に直接インストールできるボタンが準備されています。これをクリックしましょう。
インストールが完了すると、いくつかのファイルが追加されたり、ファイルが勝手に変更されたりします。特にApp.vue
やmain.js
の内容は勝手に書き換わってしまうため、開発をはじめる前にインストールしておいた方が良いでしょう。
Vue Routerで追加されるファイル群
Vue Routerをインストールすると、いくつかファイルが追加されたり、変更されます。
/src/route
index.js
というファイルが配置されていて、ここでルーティングの設定が行われます。
/src/views
「ビューファイル」と呼ばれる
<router-link to="/new">New</router-link> |
合わせて/src/App.vue
ファイルの画面上部にナビゲーション要素が追加されます。
メモの作成画面を作ろう
それではまずは、メモを作成する画面を作りましょう。src/App.vue
を編集して、次の部分を確認しましょう。
<nav>
<router-link to="/">Home</router-link> |
<router-link to="/about">About</router-link>
</nav>
ここでは、画面上部のナビゲーション要素を構築しています。ここで利用しているrouter-link
という要素は、Vue Routerをインストールすると利用できる要素で、リンク(<a>
)を作ることができます。
Vue Routerを利用している場合、HTMLの<a>
要素をそのまま利用してしまうと、ルーティングが正しく行われなくなってしまうため、代わりに<router-link>
を利用します。class
属性などの各種属性はそのまま利用できますが、リンク先を示す属性はhref
ではなく、to
になります。
それではここに、新しいメモを作成する画面を示す/new
を追加してみましょう。
<nav>
<router-link to="/">Home</router-link> |
<router-link to="/new">New</router-link> |
<router-link to="/about">About</router-link>
</nav>
すると、ナビゲーションに「New」が追加されました。
ただし、現状ではクリックしてもなにも起こりません。Chromeの開発者ツールを確認すると、コンソールに次のように表示され、/new
というパスがないことが分かります。
[Vue Router warn]: No match found for loccation with path “/new”
ルートを設定しよう
では、この/new
というパスを準備しましょう。/src/router/index.js
ファイルを開きます。
ここで、各パスの設定と、どんな内容が表示されるかを設定します。標準では、/
と/about
というパスが設定されていて、それぞれ「HomeView.vue」と「AboutView.vue」が利用される設定になっています。ここに、/new
の設定を追加しましょう。
10行目付近に、次のように追加します。
{
path: '/new',
name: 'new',
component: NewView
},
そして、「NewView」という定義をファイルの先頭に記述して、ここではこの後作成する「NewView.vue」というファイルと紐付けます。
import NewView from '../views/NewView.vue'
これでブラウザーに切り替えると、次のようなエラーメッセージが表示されます。
Module not found: Error: Can’t resolve ‘../views/NewView.vue’ in ‘/Users/seltzer/Sandbox/memopad-demo/src/router’
これは、まだ「NewView.vue」ファイルが準備されていないためです。続いてこれを作成しましょう。
ビューファイルを準備しよう
/src/views/
フォルダーに、新しく「NewView.vue」というファイルを作成します。
次のように入力しましょう。
<template>
<div><input type="text"></div>
<div><textarea></textarea></div>
<div class="center">
<button>保存</button>
</div>
</template>
これで画面を表示すると、図のようなフォームが表示されます。
ビューファイルでは、HTMLの基本タグ(DOCTYPEやbodyタグなど)は記述する必要がありません。これらは、/public/index.html
に記述されている内容が利用されます。
代わりに、要素全体を<template>
という特別なタグで囲む必要があります。内容は通常のHTMLがそのまま利用できます。
スタイルを調整しよう
今度はスタイルシートで少し調整していきましょう。スタイルシートは、外部のCSSファイルで制御することもできますが、ファイル内に記述してしまうと便利です。次のように<style>
タグを追加しましょう。
<style scoped>
div {
margin-bottom: 10px;
}
input[type=text] {
width: 100%;
}
textarea {
width: 100%;
height: 30em;
}
button {
width: 5em;
margin: 3px;
}
.center {
text-align: center;
}
</style>
<style>
タグにはscoped
という特殊な属性が付加されています。これは、「このファイル(コンポーネント)のみに適用するCSS」という事を示す属性で、これがないとすべての画面でスタイルが有効になってしまうため、特別な理由がなければ必ず付加しておきましょう。
全体のスタイルシートも調整しよう
全体のスタイルシートは/src/App.vue
内で定義されています。すべて削除しても良いですが、ここでは一部を活かして、次のように調整しましょう。
<style>
#app {
font-family: Avenir, Helvetica, Arial, sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
color: #2c3e50;
max-width: 600px;
margin: 0 auto;
}
h1 {
text-align: center;
}
nav {
padding: 30px;
text-align: center;
}
nav a {
font-weight: bold;
color: #2c3e50;
}
nav a.router-link-exact-active {
color: #42b983;
}
</style>
図のような画面になれば、これで登録画面の完成です。
フォームをコンポーネントにしよう
ここで作成したフォームは、この後作成する編集画面でも利用します。そのため、両方の画面で利用できるように「コンポーネント」にまとめておくことができます。コンポーネントは/src/components/
フォルダーにファイルを作成します。ここでは、MemoForm.vue
を作成しましょう。
そして、/src/views/NewView.vue
の内容をすべてコピーします。name
を登録しておきましょう。
<script>
export default {
name: 'MemoForm'
}
</script>
空っぽになった、/src/views/NewView.vue
では、今作成したコンポーネントを利用するように次のように記述します。
<template>
<MemoForm />
</template>
<script>
import MemoForm from '@/components/MemoForm.vue'
export default {
name: 'NewView',
components: {
MemoForm
}
}
</script>
作成したファイルをインポートして、これをcomponents
に宣言します。すると、<MemoForm />
として利用できるようになります。
これで再度動作を確認して、正しく動作していることを確認しましょう。これでコンポーネントに分けることができました。他の画面でも利用できるようになります。
Vuexで状態管理をしよう
ここで、作成したメモのデータはどこに保存したら良いでしょう? Vueだけを利用する場合には変数などに記憶しておくだけでよいですが、Vue Routerを利用した複数のページ構成があるプロジェクトの場合、変数に保存するだけでは画面を移動した時に消えてしまいます。
そこで、「状態管理」というしくみを使います。これには、状態管理ライブラリーを利用すると良いでしょう。Vueでは「Vuex」というしくみがよく使われています。
それでは、このプラグインをインストールしましょう。Vue UIで「プラグイン」を選びます。Vuexも非常によく使われるライブラリーなため、画面上部にボタンがあるのでこれをクリックしましょう。
インストールが終わると、次のファイルが追加・変更されています。
/src/store/index.js
Vuexの「ストアー」というしくみを利用するためのファイルです。あらかじめ必要な記述が含まれているので、ここにプログラム内容などを書き加えていくことになります。
main.js
Vuexを利用するための宣言が追加されます。
それでは、Vuexを利用してみましょう。
Vuexにデータを保存しよう
それでは、Vuexにデータを保存してみましょう。まずは、フォームとの連携はせずに「ボタンを押したらてきとうなデータが保存される」というところまで作成してみましょう。
/src/store/index.js
をエディターで開きます。ここには、次のような記述が続いています。
- state: アプリケーション全体でアクセスできるデータを宣言します
- getters: stateの内容を取得するためのメソッドを定義します
- mutations: stateの内容に変化を与えるためのメソッドを定義します
- actions: 非同期処理をするための処理を定義します
- modules: 処理をモジュールに分割した時の処理を定義します
この記事では、「actions」「modules」については触れませんので、公式リファレンスなどをご参照ください。
まずは、「state」に保存する内容の入れ物を定義します。ここでは、メモを保管するための「memos」という配列を準備しましょう。次のように書き加えます。
state: {
memos: []
},
そしたら、このステートにメモの内容を保存するための処理を「mutations」に定義します。次のように追加しましょう。
mutations: {
/* メモを保存する */
save (state, newMemo) {
state.memos.unshift(newMemo)
}
}
これで準備完了です。定義した「memos」というステートにアクセスするにはstate.memos
と記述します。これは先に配列として定義したためunshift
メソッドを使って、先頭に要素を追加しました。
mutationsの定義では、1つめのパラメーターとして「state」を指定する決まりがあります。実際のパラメーターは2つめ以降に指定しましょう。
これで準備完了です。
イベントを定義しよう
では次に、/src/components/MemoForm.vue
を編集して、ボタンをクリックしたらデータが保存されるようにしましょう。
まずは、JavaScriptの決まり文句を記述します。
<script>
export default {
}
</script>
ここに処理を追加します。なお、この記事ではVueの基本的な内容は省略するため、あいまいな場合はVue自体についての学習をしてみましょう。
ここでは、ボタンをクリックした時のメソッドを定義します。
methods: {
save() {
let memo = {
title: 'メモのタイトルです',
content: 'メモの内容です'
}
this.$store.commit('save', memo)
}
}
mutationsに定義したミューテーションには、this.$store.commit
というメソッドを使って呼び出します。1つめのパラメーターにミューテーションの名前、2つめ以降のパラメーターに必要なパラメーターを指定します。ここでは、仮の内容を作って指定しました。
そしたらこのメソッドを、「保存」ボタンをクリックするタイミングで発動させます。ボタンを次のように変えましょう。
<button @click="save">保存</button>
これで完成しました。
Vue.js devtoolsで動作を確認しよう
これで、新しいメモを作成して「保存」ボタンをクリックすると、ストアにデータが保存されます。ただし現状では、その様子を確認することができません。
そこで、Google Chromeに「Vue.js devtools」という拡張機能をインストールしましょう。
インストールすると、ツールバーに図のアイコンが追加されますが、実際には「開発者ツール」を起動して利用します。Vueで作成されたページを表示すると、開発者ツールに「Vue」というタブが追加されます。
ここで、動作しているプログラムのさまざまな情報が確認できます。Vuexタブをクリックしましょう。図のようにステートの内容が表示され、データが追加されている様子が確認できます。
フォームと接続しよう
では、実際にフォームと接続しましょう。まずは、data
を定義します。
// /src/components/MemoForm.vue
data() {
return {
title: '',
content: ''
}
},
そして、これをv-model
ディレクティブでフォームの項目と接続します。
<!-- /src/components/MemoForm.vue -->
<div><input type="text" v-model="title"></div>
<div><textarea v-model="content"></textarea></div>
これで、フォームに入力した内容を扱えるようになります。save
メソッドの内容を変更して、フォームの内容を保存するように変更しましょう。
// /src/components/MemoForm.vue
save() {
let memo = {
title: this.title,
content: this.content
}
this.$store.commit('save', memo)
}
これで、実際にフォームに入力した内容がストアに保存されるようになりました。
IDを挿入しよう
複数のデータがある場合は、それを特定できる「キー」を設定しておくと、後で扱いやすくなります。ここでは、ストアのミューテーションでIDを割り振れるようにしましょう。まずは、件数を記録するcount
というステートを定義しておきます。
// /src/store/index.js
state: {
count: 0,
memos: []
},
そしたら、保存するメモの内容にIDを指定してから保存します。これは、count
を1ずつ加えながら、新しいIDを割り振っていきましょう。
// /src/store/index.js
save (state, newMemo) {
newMemo.id = ++this.state.count
state.memos.unshift(newMemo)
}
こうして、メモを保存すると新しいIDが割り振られてストアに保存されていきます。
トップページに戻そう
現状では、新しいメモを保存しても画面がそのままのため、同じメモが何度も保存されてしまいます。そこで、保存できたらホームの画面に移動しましょう。これには、$router.push
というメソッドを使います。save
メソッドに以下のように追加しましょう。
// /src/components/MemoForm.vue
save() {
...
this.$router.push('/')
}
一覧画面を作成しよう
続いて、保存したメモを一覧できる画面を作成しましょう。これは、このプロジェクトのトップページに実装したいため、すでに準備されているHomeView.vue
を変更していきましょう。
次のようにファイルに書き込みます。
<template>
<div class="home">
<ul>
<li></li>
</ul>
</div>
</template>
ここに、ストアに保存されているメモの一覧を表示しましょう。JavaScriptを記述していきます。
<script>
export default {
name: 'HomeView',
computed: {
memos () {
return this.$store.state.memos
}
}
}
</script>
ここでは、「computed」にストアのメモの配列を取得するための「memos」を定義しました。これを使って、v-for
ディレクティブを作成していきます。
<li>
タグを次のように変更しましょう。
<li v-for="memo in memos" :key="memo.id">
{{ memo.title }}
</li>
これでブラウザーを確認してみましょう。現状ではストアの内容が空っぽに戻ってしまうため、画面が真っ白になってしまいます。「New」をクリックして、何度か保存ボタンをクリックしてから、「Home」に戻ってみましょう。一覧が表示されます。
メモがないときの画面を作成しよう
メモが一件もない場合、現状では画面が真っ白になってしまいます。そこで、v-if
ディレクティブを使ってメモがある時の表示とない時の表示を切り替えましょう。次のように変更します。
<div class="home">
<ul v-if="hasMemos">
<li v-for="memo in memos" :key="memo.id">
{{ memo.title }}
</li>
</ul>
<p v-else>メモはありません</p>
</div>
「hasMemos」は、「computed」で次のように宣言します。
hasMemos() {
return this.$store.state.memos.length
}
ゲッターを宣言しよう
ストアーには「ゲッター」を宣言することができます。これは、ステートの値を取得するための専用のメソッドです。先のプログラムで、メモの件数を取得するのに、直接配列のlength
プロパティを使って件数を調べていましたが、このような場合はゲッターを宣言しておいた方が、後でプログラムを拡張したりするときに拡張しやすくなります。
そこで、ここではgetCount
というゲッターを宣言してみましょう。
/src/store/index.js
を編集しましょう。getters
の部分に次のように定義します。
getters: {
getCount: (state) => {
return state.memos.length
}
}
そしたら、/src/views/HomeView.vue
の中では次のように、このゲッターを呼び出して利用します。
hasMemos() {
return this.$store.getters.getCount
}
これで、メモの件数を取得でき、それによってリストの表示を変えられるようになりました。
スタイルを調整しよう
最後にHomeView.vue
ファイルのスタイルを調整しておきましょう。次のように追加します。
<style scoped>
ul {
margin: 0;
padding: 0;
}
li {
list-style: none;
border-bottom: 1px solid #ccc;
padding-bottom: 10px;
margin-bottom: 10px;
}
li a {
color: #999;
text-decoration: none;
width: 100%;
display: block;
}
</style>
これで、一覧画面の完成です。
詳細・編集画面を作成しよう
続いて、一覧画面からメモをクリックしたら、内容を確認したり修正・削除できる画面を作りましょう。ここでは、新しいルート定義として/edit
を定義します。
/src/router/index.js
ファイルを編集します。15行目付近に次のように追加しましょう。
{
path: '/edit',
name: 'edit',
component: EditView
},
ファイルの先頭にコンポーネントの宣言も追加します。
import EditView from '../views/EditView.vue'
そしたら、ここで宣言したEditView.vue
ファイルを作成しましょう。次のように内容を追加します。
<template>
Edit View
</template>
次のようにアドレスを直接指定すると、「Edit」などと表示されていれば完了です。
http://localhost:8080/#/edit
パラメーターを受け取ろう
ここで、編集画面では「どのメモを表示するか」を指定する必要があります。このような場合、通常のウェブのシステムではアドレスにIDなどを指定する設計にする事が多いでしょう。
例)
http://localhost:8080/#/edit/1
http://localhost:8080/#/edit/2
このようなアドレスを指定できるようにするには、ルートの定義でパラメーターを受け取れるようにします。/src/router/index.js
を編集しましょう。
path: '/edit/:id',
これで、上記のようなアドレスが指定できます。今度はここで指定された内容をプログラムで利用できるようにしましょう。
アドレスで指定されたパラメーターを利用するには$route.params.(パラメーター名)
として利用できます。例えばここでは、id
というパラメーター名で定義しているので、次のようにすると画面にパラメーターを表示することができます。
Edit view: {{ $route.params.id }}
メモを呼び出そう
こうして、アドレスで特定のメモを指定できるようになったので、これを呼び出して取り出せるようにしましょう。
まずは、ストアでゲッターを定義します。
// /src/store/index.js
getMemoById: (state) => (id) => {
return state.memos.find(memo => memo.id === id)
},
配列のfind
メソッドを使って、指定されたidと一致するメモを取得することができます。これを使って、編集画面でメモを取り出してみましょう。
<script>
// /src/views/EditView.vue
export default {
name: 'EditView',
computed: {
memo() {
let id = parseInt(this.$route.params.id)
return this.$store.getters.getMemoById(id)
}
}
}
</script>
これでmemo
で内容を取得できるようになったので、<template>
内を次のように変更しましょう。
<template>
{{ memo.title }}
</template>
一覧画面と連携しよう
ここまでできたら、一覧画面でメモをクリックしたら画面が切り替わるようしましょう。次のように<router-link>
でリンクを張ります。
<!-- /src/views/HomeView.vue -->
<router-link :to="{ name: 'edit', params: { id: memo.id } }">{{ memo.title }}</router-link>
<router-link>
でパラメーターを渡す場合は、定義したルートの名前などを利用して指定する必要があります。これで、次のようなアドレスが作られるようになります。
http://localhost:8080/#/edit/1
コンポーネントに表示しよう
続いて、メモ作成画面で作ったコンポーネントを使って、編集画面に仕上げていきましょう。
まずは、コンポーネントにメモの情報を渡せるように変更していきます。コンポーネントが値を受け取れるようにするにはprops
というしくみを利用します。次のように宣言しましょう。
// /src/components/MemoForm.vue
props: [
'memo'
],
これにより、コンポーネントを呼び出すときに次のように属性を指定できるようになります。メモ作成画面を次のように変更しておきましょう。
<!-- /src/views/NewView.vue -->
<MemoForm :memo="" />
これで準備完了です。
では、同じようにしてEditView.vue
を変更していきましょう。
<template>
<!-- /src/views/EditView.vue -->
<MemoForm :memo="memo" />
</template>
<script>
import MemoForm from '@/components/MemoForm.vue'
export default {
name: 'EditView',
components: {
MemoForm
},
computed: {
memo() {
let id = parseInt(this.$route.params.id)
return this.$store.getters.getMemoById(id)
}
}
}
</script>
これでコンポーネントに、メモの内容が渡されるようになったので、これを使ってフォームに初期値を設定していきます。再びMemoForm.vue
を編集して、data
の定義を次のように変更しましょう。
// /src/components/MemoForm.vue
data() {
return {
title: this.memo.title,
content: this.memo.content
}
},
これで、メモの内容がフォームに反映されるようになりました。
パラメーターが正しくない場合の処理をしよう
アドレスはユーザーが自由に書き換えられてしまうため、存在しないIDを指定してしまったり、いたずらでおかしな値を指定されることが考えられます。そこで、v-if
ディレクティブを使ってコンポーネントの表示を制御しましょう。
<!-- /src/views/EditView.vue -->
<MemoForm :memo="memo" v-if="memo" />
<p v-else>指定されたメモはありません</p>
メモを編集できるようにしよう
現状では、編集フォームでメモの内容を変更すると、新しいメモとして登録されてしまいます。そこで、save
メソッドを改良して、既存のメモの場合は内容を変更するようにしましょう。
// /src/components/MemoForm.vue
save() {
let memo = {
title: this.title,
content: this.content
}
if (this.memo.id) {
memo.id = this.memo.id
}
this.$store.commit('save', memo)
this.$router.push('/')
},
既存のメモの場合、「memo.id」に値が挿入されているため、これを合わせてストアーのsaveに送るようにします。
そしたら、ミューテーションを次のように変更しましょう
// /src/store/index.js
save (state, newMemo) {
if (newMemo.id) {
let x = state.memos.find(memo => memo.id === newMemo.id)
x.title = newMemo.title
x.content = newMemo.content
} else {
newMemo.id = ++this.state.count
state.memos.unshift(newMemo)
}
こちらも、id
が渡された場合は、メモの変更になるので、既存の配列の内容を変更するように変更しました。これによって、メモの変更が行えるようになりました。
メモを削除しよう
次は、メモの削除のしくみを作成しましょう。まずは、ストアで特定のデータを削除するミューテーションを定義します。
// /src/store/index.js
delete (state, id) {
state.memos = state.memos.filter(memo => memo.id !== id)
}
配列のfilter
メソッドを使って、指定されたID以外のデータだけを抽出し、それを改めてステートに保存し直します。これによって、IDで指定したメモのデータだけが除外されるというしくみです。
では、ここで作ったミューテーションを呼び出していきましょう。編集画面に「削除」ボタンを追加します。
<!-- /src/components/MemoForm.vue -->
<div class="center">
<button @click="save">保存</button>
<button @click="remove" v-if="memo.id">削除</button>
</div>
v-if
ディレクティブで、memo.id
がある場合のみ、つまり編集画面の場合だけ、ボタンを表示するようにしました。クリックするとremove
が呼び出されます。これを定義しましょう。
// /src/components/MemoForm.vue
methods: {
...
remove() {
this.$store.commit('delete', this.memo.id)
this.$router.push('/')
}
}
これで、メモが削除されるようになりました。
vue-persistでデータを保存しよう
これで、メモ機能の一連の流れができあがりました。ただし、このメモツールは、ブラウザーを閉じたり、再読込するとデータが消えてしまいます。これは、JavaScriptの変数上にしかデータが存在していないためです。
そこで、このデータをブラウザーの「ローカルストレージ」と呼ばれる記憶領域に保存して、同じウェブブラウザー上であれば利用し続けられるようにしましょう。
これには、「vuex-persist」というライブラリを利用するのが簡単です。
Vue UIを起動したら、「依存」をクリックして「依存をインストール」をクリックします。
検索窓に「vuex-persist」と入力して、ライブラリを探しましょう。これをインストールします。
vuex-persistを利用する場合は、ほとんど決まり文句を記述するだけです。ストアに、次のように追加しましょう。
// /src/store/index.js
import { VuexPersistence } from 'vuex-persist'
...
const vuexPersist = new VuexPersistence({
storage: localStorage
})
mutations: {
RESTORE_MUTATION: vuexPersist.RESTORE_MUTATION,
...
plugins: [vuexPersist.plugin]
vuex-persist
を利用して、保存先を「localStorage」に設定します。後は、ミューテーションの時にvuex-persistを利用するように設定しています。
これで、メモの内容がローカルストレージに移されます。Chromeの開発者ツールで「アプリケーション→ローカルストレージ」を確認すると、ストアの内容が記憶されていることが分かります。これでメモを作成すると、ブラウザーを終了して、再度起動しても内容が呼び戻されるようになります。
これで、Vueを利用したメモツールが完成しました。さまざまな知識が出てきてややこしく感じますが、Vueの基本をしっかり押さえ、VuexとVuex Routerの使い方を学べば、さまざまなツールが開発できるようになるため、ぜひ利用してみましょう。