Vue.jsで単純なものを作るとリロードしたときに初期状態に戻ってしまって儚い(はかない)。。かといってデータベースと連携したものをつくるのはまだハードルが高い。前段階として以前にも触れたLocalstrageと連携して値を保存してみたい。公式サイトのサンプルにlocalStorageと連携したTodoリストがあったのでコードを読み解いてみました。それではどーぞ!
【目次】
※参考:【JS】ローカルストレージの値をリンク先のフォームのinputタグのvalueに渡す! - クモのようにコツコツと
Todoリスト完成品
まずは完成品から。公式サイトのこちらのサンプルにある「TodoMVC」を元にしている。
※参考:TodoMVC — Vue.js
See the Pen Vue de Localstarage by イイダリョウ (@i_ryo) on CodePen.
テキストを日本語にしてみた。(敬意を評してフッターのクレジットはそのまま残した)
- 「やること」に何か予定を入れると下に追加される
- 予定チェックを入れると打ち消し線が入って完了済みになる
- 下のタブで「すべて」「未完了」「完了済み」の絞り込み表示ができる
- 右下の「すべて削除」で初期状態にもどる
何か予定を入れた状態でリロードしていただくと、その状態がそのまま保持された!
localStorageに保存されているためだ。
//キー名 todos-vuejs-2.0 //値 [ { "id":1, "title":"買い物に行く", "completed":false}, {"id":2, "title":"本当に行く", "completed":false}, {"id":3, "title":"絶対にいく", "completed":false} ]
キー名はtodos-vuejs-2.0
で値は配列の中にJSON形式で入っている。
データはブラウザの中に保存されているため別のブラウザや端末には値を連携できないが、リロードによる「儚さ(はかなさ)」はだいぶ薄れたw
HTMLコード
全体像
まずは大枠のタグ構成から見ていく。
<section class="todoapp"> <header class="header"> <!--やること入力欄(省略)--> </header> <section class="main" v-show="todos.length" v-cloak> <!--やることリスト本体(省略)--> </section> <footer class="footer" v-show="todos.length" v-cloak> <!--タブメニュー(省略)--> </footer> </section>
- Todoリスト全体は
todoapp
.header
はやることの入力欄.main
はやることリスト本体でv-show
とv-cloak
がある。. footer
はタブメニューでここにもでv-show
とv-cloak
がある。
初期状態では.main
と. footer
は非表示。v-show
でその設定をしてそう。v-show
はv-if
と同様、Vue.jsの独自属性で分岐処理。
※参考:【Vue.js】イベント(v-on)、分岐(v-show、v-if)、ループ(v-for)をやってみた! - クモのようにコツコツと
v-cloak
はCSSに関連する属性で後述する。
やること入力欄
やること入力欄に当たる.header
から見ていく
<header class="header"> <h1>やること</h1> <input class="new-todo" autofocus autocomplete="off" placeholder="なにする?" v-model="newTodo" @keyup.enter="addTodo"> </header>
input
タグにv-model
属性と@keyup.enter
がある。
autofocus
やautocomplete
は馴染みが薄かったが、フォーム読み込み時のフォーカス設定をするinputタグデフォルトの属性だった。
※参考:<input autofocus>-HTML5タグリファレンス
※参考:<input autocomplete>-HTML5タグリファレンス
v-model
はVue.jsの独自属性でデータバインディング(フォームの入力値をリアルタイムに反映する)。
※参考:【Vue.js】v-modelデータバインディング事始め(リンダリンダの歌詞を変えてオリジナルラブソングを作る) - クモのようにコツコツと
@
はVue.jsの省略記法でv-on
のこと。
v-on
はイベント設定の属性。
※参考:【Vue.js】イベント(v-on)、分岐(v-show、v-if)、ループ(v-for)をやってみた! - クモのようにコツコツと
keyup.enter
ということでエンターキーを押した時のイベントと紐づいている。
この入力欄に打った内容がリアルタイムに下のやることリストに表示されたり、キーを叩いた時に発火するイベントが書かれている。
やることリスト本体
次、やることリスト本体に当たる.main
。
<section class="main" v-show="todos.length" v-cloak> <input id="toggle-all" class="toggle-all" type="checkbox" v-model="allDone"> <label for="toggle-all"></label> <ul class="todo-list"> <li v-for="todo in filteredTodos" class="todo" :key="todo.id" :class="{ completed: todo.completed, editing: todo == editedTodo }"> <!--リストの中身(省略)--> </li> </ul> </section>
#toggle-all
にv-model
がある。- lavelタグは
#toggle-all
と紐づいている .todo-list
はulタグでやることリスト本体.todo
がはliタグでリストの1件単位。v-for
でループ。
:key
で入力内容を追跡。:class
でclass名を指定。
v-model
は前述の通りデータバインディング。このinputタグは「全て選択」のチェックボックスなのでチェックの切替に対する反映。
v-for
はVue.jsの独自属性でループ設定。これでリストが件数分表示される。
※参考:【Vue.js】イベント(v-on)、分岐(v-show、v-if)、ループ(v-for)をやってみた! - クモのようにコツコツと
:
はVue.jsの省略記法でv-bind
のこと。
v-bind
はVue.jsの独自属性でタグの属性を指定できる。
※参考:【Vue.js】v-bindでclass名を動的に追加、削除する!(北斗の拳の名言編) - クモのようにコツコツと
:key
は入力内容の追跡だがv-for
の実行のために必要とのこと。
※参考:v-forで配列を表示する[v-bind:key][index][Vue.js]
:class
はclassの指定だが値にcompleted
、editing
とあるので完了済や編集中で見た目を変える設定と紐づいていそう。
リストの中身
次、リスト(li
)の中身。
<li v-for="todo in filteredTodos" class="todo" :key="todo.id" :class="{ completed: todo.completed, editing: todo == editedTodo }"> <div class="view"> <input class="toggle" type="checkbox" v-model="todo.completed"> <label @dblclick="editTodo(todo)">{{ todo.title }}</label> <button class="destroy" @click="removeTodo(todo)"></button> </div> <input class="edit" type="text" v-model="todo.title" v-todo-focus="todo == editedTodo" @blur="doneEdit(todo)" @keyup.enter="doneEdit(todo)" @keyup.esc="cancelEdit(todo)"> </li>
- divタグの
. view
、inputタグの. edit
がある。 . view
の中にはinputタグの. class
、labelタグ、buttonタグの. destroy
がある。. class
にv-model
がある。- labelタグには
@dblclick
がある。中身はマスタッシュタグ{{ }}
- buttonタグの
. destroy
には@click
がある。 - inputタグの
.edit
にはv-model
、v-todo-focus
、@blur
、@keyup.enter
、@keyup.esc
がある。
さすがにここはリスト自体にあたるのでVue.jsの属性が連続コンボ!v-model
と@
(v-on
の省略記号)は前述の通り。
v-todo-focus
はtodo
名前的にもVue.jsのデフォルトの属性ではなさそう。調べたところVue.jsではカスタムでディレクティブを設定できるようだ。
inputタグの.toggle
は完了にするチェックボックスなのでv-model
でリアルタイムにそれが反映する。
labelはマスタッシュタグ{{ }}
でリストのテキストが表示されるが中にダブルクリックのイベントが紐づいている。
buttonタグの. destroy
にはクリックイベントが仕掛けられていて、クリックすると削除になる。
inputタグの.edit
だがここは文字入力がないので謎の存在だった。上のlabelをダブルクリックすると文字が変更できるようになる!それがこinputタグだ。
@blur
はフォーカスが外れた時のイベント。
※参考:【Vue.js】イベントハンドリングをサンプルを作りながら理解する - Qiita
他にエンターキーやESCキーのイベントも書かれている。
タブメニュー
最後に. footer
。タブメニューの部分。
<footer class="footer" v-show="todos.length" v-cloak> <span class="todo-count"> <strong>{{ remaining }}</strong> {{ remaining | pluralize }} 未完了 </span> <ul class="filters"> <li><a href="#/all" :class="{ selected: visibility == 'all' }">すべて</a></li> <li><a href="#/active" :class="{ selected: visibility == 'active' }">未完了</a></li> <li><a href="#/completed" :class="{ selected: visibility == 'completed' }">完了済み</a></li> </ul> <button class="clear-completed" @click="removeCompleted" v-show="todos.length > remaining"> すべて削除 </button> </footer>
- spanタグ
.todo-count
の中にマスタッシュタグがある - ulタグ
. filters
はタブメニュー部分。中のliタグがタブ - それぞれのliタグ中のaタグには
:class
がある。 - 最後のbuttonタグ
clear-completed
は全削除ボタン。@click
とv-show
がある。
spanタグのマスタッシュタグ{{ }}
でリストの件数が表示される。
リストがタブメニューで:class
で選択された時のclass設定が紐付けられている。
buttonタグは全削除ボタンでクリックイベントが仕掛けられている。
CSS
Vue.js固有の設定のみピックアップ
/*マスタッシュの非表示設定*/ [v-cloak] { display: none; } /* index.cssのスタイル(後略)*/
v-cloak
はページ読み込み時にマスタッシュ{{ }}
が一瞬表示されないようにする設定。プロパティを角カッコ[ ]
で囲っているのが特徴的。
※参考:【Vue.js】{{ … }} を表示させない(v-cloak) | 西住工房
以降はサンプルのindex.css
のスタイルで一般的な内容なので省略するが、下記のような参考になるスタイルが見受けられた。
- チェックマークのSVG画像をDeta URIで直接埋め込む
- 「完了済み」に打ち消し線(
line-through
)を設定する
次回、JS編に続く…
長くなったので2回に分けます。次回、JS編です。
HTMLを見た限り、v-cloak
とカスタムディレクティブは初めてだったけど基本はこれまでに触れてきた基本的なv-
系の組み合わせなことがわかりました。
v-
と省略記号@
、:
を覚えておけばVue.jsの独自属性は識別しやすそう。
次回はいよいよ、JSコードの中にlocalStrageに関する処理が見つかると思うので楽しみです。それではまた!
※続き書きました!
※参考:Vue.jsの習得のためにやったことまとめ
qiita.com