Vue.jsシリーズ、公式サイトのサンプルにあったlocalStorageと連携したTodoリストのコードを読み解く。前回はHTML、CSS編でした。今回はJS編。localStorageと関わる部分を見たかったけどボリュームがあったのでまずは全体像から。それではいきましょう!
【目次】
※前回:【Vue.js】localStorageと連携したTodoリストを読み解く(HTML、CSS編) - クモのようにコツコツと
Todoリスト完成品
まずは完成品、こちらです。
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} ]
localStorageについてはこちらを参照。
※参考:【JS】ローカルストレージの値をリンク先のフォームのinputタグのvalueに渡す! - クモのようにコツコツと
前回、HTMLタグの中にv-xxx
、:
、@
などVue.jsの独自属性がたくさんあった。JSにそれらと紐づいた処理が書かれているはず。
JS
JSコードを見ていく。
JSコード全体
コード全体はこちら。結構ボリューミー。。
// Full spec-compliant TodoMVC with localStorage persistence // and hash-based routing in ~120 effective lines of JavaScript. // localStorage persistence var STORAGE_KEY = 'todos-vuejs-2.0' var todoStorage = { fetch: function () { var todos = JSON.parse(localStorage.getItem(STORAGE_KEY) || '[]') todos.forEach(function (todo, index) { todo.id = index }) todoStorage.uid = todos.length return todos }, save: function (todos) { localStorage.setItem(STORAGE_KEY, JSON.stringify(todos)) } } // visibility filters var filters = { all: function (todos) { return todos }, active: function (todos) { return todos.filter(function (todo) { return !todo.completed }) }, completed: function (todos) { return todos.filter(function (todo) { return todo.completed }) } } // app Vue instance var app = new Vue({ // app initial state data: { todos: todoStorage.fetch(), newTodo: '', editedTodo: null, visibility: 'all' }, // watch todos change for localStorage persistence watch: { todos: { handler: function (todos) { todoStorage.save(todos) }, deep: true } }, // computed properties // http://vuejs.org/guide/computed.html computed: { filteredTodos: function () { return filters[this.visibility](this.todos) }, remaining: function () { return filters.active(this.todos).length }, allDone: { get: function () { return this.remaining === 0 }, set: function (value) { this.todos.forEach(function (todo) { todo.completed = value }) } } }, filters: { pluralize: function (n) { return n === 1 ? '件' : '件' } }, // methods that implement data logic. // note there's no DOM manipulation here at all. methods: { addTodo: function () { var value = this.newTodo && this.newTodo.trim() if (!value) { return } this.todos.push({ id: todoStorage.uid++, title: value, completed: false }) this.newTodo = '' }, removeTodo: function (todo) { this.todos.splice(this.todos.indexOf(todo), 1) }, editTodo: function (todo) { this.beforeEditCache = todo.title this.editedTodo = todo }, doneEdit: function (todo) { if (!this.editedTodo) { return } this.editedTodo = null todo.title = todo.title.trim() if (!todo.title) { this.removeTodo(todo) } }, cancelEdit: function (todo) { this.editedTodo = null todo.title = this.beforeEditCache }, removeCompleted: function () { this.todos = filters.active(this.todos) } }, // a custom directive to wait for the DOM to be updated // before focusing on the input field. // http://vuejs.org/guide/custom-directive.html directives: { 'todo-focus': function (el, binding) { if (binding.value) { el.focus() } } } }) // handle routing function onHashChange () { var visibility = window.location.hash.replace(/#\/?/, '') if (filters[visibility]) { app.visibility = visibility } else { window.location.hash = '' app.visibility = 'all' } } window.addEventListener('hashchange', onHashChange) onHashChange() // mount app.$mount('.todoapp')
JS全体像
まずは一番外側の塊から見ていき、全体像をイメージしたい。処理部分を省略したのがこちら。
// Full spec-compliant TodoMVC with localStorage persistence // and hash-based routing in ~120 effective lines of JavaScript. // localStorage persistence var STORAGE_KEY = 'todos-vuejs-2.0' var todoStorage = { //処理 } // visibility filters var filters = { //処理 } // app Vue instance var app = new Vue({ //処理 }) // handle routing function onHashChange () { //処理 } window.addEventListener('hashchange', onHashChange) onHashChange() // mount app.$mount('.todoapp')
うむ、コンパクトになった♪
冒頭のコメント
コメントを和訳してみる。
localStorage持続性を備えた完全仕様準拠のTodoMVC そしてJavaScriptの120行までの有効な行でハッシュベースのルーティング。
変数STORAGE_KEY
と変数todoStorage
次のコメントを和訳。
localStorageの持続性
ここら辺にlocalStorageの処理が書かれていそう。
変数filters
可視性フィルタ
可視性フィルタとはなんだろう。
変数app
app Vueインスタンス
ここでVueインスタンスが作られている。
関数onHashChange()
ルーティングを処理する
ルーティング。ハッシュチェンジ。切り替え系の処理が書かれていそう。そしてすぐ下にハッシュチェンジhashchange
のイベントリスナとonHashChange()
関数実行が書かれている。
ハッシュチェンジとはページ内リンクでURLの後ろに付く#hoge
などのこと。
※参考:onhashchange - フラグメント識別子の変更時に発火する
マウント
最後にマウント。
vm.$mount( [elementOrSelector] )
vm
オブジェクトに$mount()
メソッドが続く。jQueryみたいな$
付きのメソッドだがVue.js独自のメソッドのよう。
Vue インスタンスがインスタンス化において el オプションを受け取らない場合は、DOM 要素は関連付けなしで、”アンマウント(マウントされていない)” 状態になります。vm.$mount() は アンマウントな Vue インスタンスのマウンティングを手動で開始するために使用することができます。
※参考:API — Vue.js
ふむ。確かに後述するVueインスタンスの中にはel
オプションはない。その代わりにここで. todoapp
タグの紐づけているわけか。
Vueインスタンス全体像
次にVueインスタンスの全体像を見ていく。
// app Vue instance var app = new Vue({ // app initial state data: { //処理 }, // watch todos change for localStorage persistence watch: { //処理 }, // computed properties // http://vuejs.org/guide/computed.html computed: { //処理 }, filters: { //処理 }, // methods that implement data logic. // note there's no DOM manipulation here at all. methods: { //処理 }, // a custom directive to wait for the DOM to be updated // before focusing on the input field. // http://vuejs.org/guide/custom-directive.html directives: { //処理 } })
変数app
でVueインスタンスを作成している。また、コメントを和訳してみる。
data
オプション
アプリ初期状態
watch
オプション
localStorageの持続性のためにタスクの変更を監視する
localStorageの監視関係の処理がここに書かれていそう。
watch
についてはこちらの記事も参照。
※参考:【Vue.js】watch(監視プロパティ)で戦国時代クイズを作った - クモのようにコツコツと
computed
オプション
計算プロパティ
計算系の処理がかかれていそう。
コメントのリンク先はこちら。英語ページです。
※参考:Redirecting...
computed
についてはこちらも参照。
※参考:【Vue.js】computed(算出プロパティ)で割り勘アプリを作る(おまけでこち亀アプリも) - クモのようにコツコツと
filtersオプション
先ほど変数filters
が出てきたので、関係していそう。
filters
オプションはあまり触れる機会がなかった。公式サイトを見てみる。
※参考:フィルター — Vue.js
methodsオプション
データロジックを実装するメソッド。 DOMの操作はまったくありません。
名前の通りメソッドの処理が書かれている。おなじみのオプション。
directivesオプション
directivesオプションって初めて見た。
DOMが更新されるのを待つカスタムディレクティブ 入力フィールドに注目する前に
DOMおん更新に対する処理が書かれているようだ。
directives
オプションは初めて見た。
公式サイトを見てみる。
続きます…
全体像だけでもボリュームがあったので、処理の詳細については次回に見ていきます。それではまた!
※続き書きました!
※参考:Vue.jsの習得のためにやったことまとめ
qiita.com