Skip to content

Instantly share code, notes, and snippets.

@koba04
Last active November 2, 2024 00:52
Show Gist options
  • Save koba04/9776792 to your computer and use it in GitHub Desktop.
Save koba04/9776792 to your computer and use it in GitHub Desktop.
Vue.js note(v0.10.3). not translate. This is draft of https://github.com/koba04/vuejs-book .

API

Class: Vue

  • Vueはvue.jsのコアとなるコンストラクタ

  • インスタンスが作られたときにデータバインディングが開始される

  • オプションを取ることも出来て、DOMやデータやメソッドについて定義出来る

  • コンパイルフェイズでは、DOMやdirectiveの内部を捜査する

  • 一度コンパイルされるとViewModelによって管理される

  • 一つのDOMを管理出来るのは一つのViewModelだけ

  • すでにコンパイルされている要素に対して再度ViewModelを作ったりしてコンパイルすると既存のバインディングの情報が失われるので、コンパイル済みの要素に対して再度コンパイルすべきではない

  • テンプレートの要素はDocumentFragmentsによってキャッシュされて効率的に再利用される

  • ViewModelのインスタンスは$elによってDOMと関連付けられる(MVVMのV)

  • また$dataによっても関連付けられる(MVVMのM)

  • それぞれは双方向にバインディングされる

  • ViewModelのインスタンスは$dataへのアクセスをプロキシしていて、vm.$data.msgはvm.msgとして参照出来る

  • しかしながらそこには違いがあってvmの形式では他のViewModelをdataとして扱うことは出来ない

  • おそらくViewModelのdataに他のViewModelを指定すると、ViewModelの指定された側のViewModel側には変更が反映されないことを言っている?

  • http://jsfiddle.net/koba04/PY2Q2/

  • dataオブジェクトは一つのViewModelだけに属している必要はなくて複数のViewModelから参照することも出来る

  • これは複数のcomponentがグローバルなオブジェクトを共有して反応する必要があるときに便利

  • ViewModelはいくつかのメソッドを持っていてデータやイベントやDOMを操作するのに使える

  • また、Vueのコンストラクタ自身もいくつかのメソッドを持っていて、Vueを継承したりグローバルな設定やdirectiveやcomponentを登録することが出来る

Instantiation Options

Data & Logic

data

  • ViewModelのデータでvm.$dataとしてアクセス出来る

  • ViewModelのプロパティへのアクセスはdataにプロキシされて同期される

  • データオブジェクトはJSONとして表現出来る必要がある

  • 複数のViewModelでデータを共有することが出来る

  • Vue.jsは__emitter__という隠しプロパティを持っていてプロパティへのgetter、setterでイベントを発行する

  • $と_で始まるプロパティはスキップされる

methods

  • ViewModelにミックスインされてViewModelインスタンスから直接アクセスすることが出来、directiveから呼ぶことも出来る
  • メソッドのcontextはViewModelのインスタンスになる

computed

  • getter($get)、setter($set)を定義しておくことで常に処理済みの値を返すことが出来る
var vm = new Vue({
    data: { a: 1 },
    computed: {
        // get only, just need a function
        aDouble: function () {
            return this.a * 2
        },
        // both get and set
        aPlus: {
            $get: function () {
                return this.a + 1
            },
            $set: function (v) {
                this.a = v - 1
            }
        }
    }
})
vm.aPlus // 2
vm.aPlus = 3
vm.a // 2
vm.aDouble // 4

paramAttributes

  • ViewModelに処理データとしてセットするattributeの配列
  • これが評価されるのは1度のみで、ViewModelでの変更がこの属性に反映されることはない
<div id="test" size="100" message="hello!"></div>
new Vue({
    el: '#test',
    paramAttributes: ['size', 'message'],
    created: function () {
        console.log(this.size) // 100
        console.log(this.message) // 'hello!'
    }
})

DOM Element

el

  • ViewModelに紐付けるDOM要素でquerySelectorの書式で指定する
  • vm.$elで参照することが出来る
  • これが指定されていない場合は新しいDOMのnodeが自動的に作成される

template

  • $elに挿入されるtemplateの文字列で、$elにあった要素は全て上書きされる

  • replaceオプションがtrueの場合は上書きではなくて置き換えられる

  • #から始まっている場合はquerySelectorとして評価されて、取得した要素がテンプレートととして使用される

  • Vue.jsはDOMベースのテンプレートでコンパイラーはDOMからdirectiveを探してデータバインディングを作る

  • 文字列のテンプレートの場合もDOMFragmentにしてインスタンス毎にcloneされる

  • ValidなHTMLにしたい場合はdata-属性として指定することも出来る

replace

  • テンプレートでトップレベルの要素を置き換えるかどうか

tagName

  • 作成される要素のタグの名前

id

  • 要素のid

className

  • 要素のクラス名

attributes

  • 要素の属性値

Lifecycle Hooks

  • ViewModelのインスタンスのライフサイクルに応じて'attached', 'detached', 'beforeDestroy', 'afterDestroy'といったイベントが発行される
  • イベントは'hook:eventName'の形式で発行される

created

  • コンパイルが始まる前に同期的に呼ばれる
  • $elや$dataは使えるけどDOMはまだ準備出来ていないのでデータバインディングはまだ有効でない
  • createdのフックはViewModelの初期状態に何か追加したい場合に使われる
  • createdのフックの中でセットした関数でないプロパティは後ほどdataオブジェクトにコピーされてデータバインディングが開始される
  • createdのフックの中で$watchを使う場合はデータが作られたときにも呼ばれるので変更されたときだけに呼んで欲しい場合はreadyのフックの中で使うといい

ready

  • コンパイルも終わってViewModelの準備出来たときに呼ばれる
  • readyのフックの中でプロパティを追加した場合はデータバインディングの対象にならないので注意(createdを使う)

attached

  • $elがdirectiveやインスタンスメソッドでDOMにattachされたタイミングで呼ばれる
  • $elを直接操作した場合は呼ばれない

detached

  • $elがdirectiveやインスタンスメソッドでDOMから削除されたタイミングで呼ばれる
  • $elを直接操作した場合は呼ばれない

beforeDestroy

  • ViewModelが破棄されるときに呼ばれて、データバインディングやdirectiveはまだ有効な状態になっている
  • また全ての子ViewModelも有効な状態
  • このフックはほとんど内部的に使われているものだけどcreatedやreadyのフックのクリーンアップで使うことはあるかもしれない
  • $onや$watchは$destroyの中で解除してくれるので明示的に呼ぶ必要はない

afterDestroy

  • ViewModelが完全に破棄された後に呼ばれる
  • データバインディングなども解除されている

Private Assets

  • ViewModelのコンパイルの時のみ有効なプロパティ

directives

  • ViewModelで使用できるdirective

filters

  • ViewModelで使用できるfilter

components

  • ViewModelで使用できるcomponent

partials

  • ViewModelで使用できるpartial

transitions

  • ViewModelで使用できるtransition

Others

parent

  • 親のViewModelのインスタンス
  • これはv-componentを使うのと同じようなメリットがあって親のスコープのデータをテンプレートの中で利用できる
  • 親のViewModelをvm.$parentとして参照出来る
  • 親子間でイベントを通じてやりとり出来る
  • 親が破棄された時に子も一緒に破棄される

このオプションはネストしたViewModelを扱う時にメモリ管理を行いたい時に便利

lazy

  • changeイベント(enterキー押すかフォーカスが外れる)だけでtriggerされるか全てのinputイベント(キー入力)でtriggerされるか
  • inputタグとかの話?

Instance Properties

vm.$el

  • ViewModelが管理しているDOM

vm.$data

  • ViewModelがバインディングしているデータ
  • 新しいオブジェクトに差し替えることも出来る
  • ViewModelのプロパティのようにアクセスすることも出来る

vm.$options

  • ViewModelをインスタンス化したときのオプション
  • カスタムオプションを指定した時はここから参照する

vm.$

  • v-refで指定したオブジェクトが入っている

vm.$index

  • v-repeatの中で使うとインデックスが入っている

vm.$parent

  • 親のViewModel

vm.$root

  • rootのViewModel

vm.$compiler

  • ViewModelのコンパイラーのインスタンス
  • 内部的にViewModelのデータバインディングの管理などをしているもので、基本的には使うのを避けるべき

Instance Methods

Data

  • データに対する変更の監視は全て非同期で行われる
  • 加えて変更の反映はイベントループの中でバッチとして行われる
  • ということで、同じイベントループの中で複数回データを変更してもデータご更新されるのは最新の値で一度だけ

vm.$watch( keypath, callback )

  • 指定したkeypathのデータの変更を監視してコールバックを実行する
  • コールバックには第一引数で新しい値が渡されている
  • keypathに$dataを指定することで全てのデータに対する変更を監視する可能です。

vm.$unwatch( keypath, [callback] )

  • 変更の監視をやめる
  • コールバックを渡すと監視をやめたタイミングで呼ばれる(?)

vm.$get( keypath )

  • 与えられたkeypathから値を取得する
  • 与えられたkeypathのデータが見つからなかった時は見つかるまで親のViewModelを辿っていく
  • どの親がデータを持っているかわからないときなどに便利
  • 見つからなかった場合はundefinedを返す

vm.$set( keypath, value )

  • 指定したkeypathにデータをセットする
  • keypathが存在しなかった場合は作成される

Cross-ViewModel Events

  • 複数のネストしたViewModelがあるとき、EventEmitterのようにお互いやりとり出来る

vm.$dispatch( event, [args...] )

  • イベントを発行する
  • イベントは$rootまで遡って伝わっていく

vm.$broadcast( event, [args...] )

  • 全ての子のViewModelにイベントを発行する
  • 子のViewModelのさらに子にも伝わっていく

vm.$emit( event, [args...] )

  • ViewModel自身に対してのみイベントを発行する

vm.$on( event, callback )

  • ViewModelのイベントを購読する

vm.$once( event, callback )

  • ViewModelのイベントを一度だけ購読する

vm.$off( [event, callback] )

  • 引数がない時は全てのイベントを解除する
  • イベントが与えられた時はそのイベントだけが解除される
  • イベントとコールバックが与えられた時はそのイベントの指定されたコールバックだけ解除される

DOM Manipulation

  • 全てのDOM操作はjqueryと同じように動作する
  • vue.jsのtransitionのtriggerが発行されることを除いて

vm.$appendTo( element | selector )

  • vm.$elに指定されたelementを追加する。querySelectorの文字列でも大丈夫

vm.$before( element | selector )

  • vm.$elの前にelementを追加する

vm.$after( element | selector )

  • vm.$elの後にelementを追加する

vm.$remove()

  • DOMから$elを削除する

Misc

vm.$destroy()

  • 完全にViewModelを破棄する
  • 他のViewModelとの連携、directive、DOM、$onや$watchのイベントリスナなども自動的に破棄される

Global Methods

Vue.extend( options )

  • Vueのサブクラスを作る
  • elを除くViewModelをインスタンス化する際のオプションのほとんどを使える
  • elは同じ要素に対して複数のViewModelを割り当てることは出来ないのでインスタンス化する際にしか指定出来ない

Vue.config( options | key, [value] )

  • グローバルなオプション。複数回呼ぶことが出来て値は上書きされる

  • デフォルト

{
    // prefix for directives
    prefix: 'v',
    // log debug info
    debug: false,
    // suppress warnings
    silent: false,
    // CSS class attached for entering transition
    enterClass: 'v-enter',
    // CSS class attached for leaving transition
    leaveClass: 'v-leave',
    // Interpolate mustache bindings
    interpolate: true,
    // Interpolation delimiters
    // default value translates to {{ }} and {{{ }}}
    delimiters: ['{', '}']
}

Vue.directive( id, [definition] )

  • グローバルにdirectiveを登録する

Vue.filter( id, definition )

  • グローバルにfilterを登録する

Vue.component( id, definition )

  • グローバルにcomponentを登録する

Vue.effect( id, definition )

  • グローバルにtransition effectを登録する

Vue.partial( id, definition )

  • グローバルにpartialを登録する
  • テンプレートのHTMLか#から始まっている場合はquerySelectorとして評価され、DOM elementを指定することが出来る

Vue.nextTick( callback )

  • Vue.jsはバッチでViewの更新を非同期で行う
  • nextTickは内部ではrequestAnimationFrameが使えるときは使って、使えない時はsetTimeout 0で呼ばれる
  • このメソッドは次のViewの更新を待って処理を実行したい時に便利

Vue.require( module )

  • Vue.jsが内部で使用しているモジュールにアクセスすることが出来る
  • プラグインの作成する時に使用するけど注意して使う必要がある

Vue.use( plugin, [args...] )

  • プラグインを使う
  • プラグインはオブジェクトでinstallメソッドを持っている必要がある
  • 関数として定義されていた場合はそれがinstallメソッドとして扱われる
  • 引数はinstallメソッドに渡される

Directives

Data Binding Directives

  • これらのdirectiveはViewModelのプロパティにバインドされる
  • またViewModelのコンテキストで式が評価される

v-text

  • elementのtextNodeとして更新される
  • {{ Mustache }}で書いた場合もv-textとしてコンパイルされる

v-html

  • elementのinnerHTMLとして更新される
  • ユーザーの入力をv-htmlで使うのは危険で安全なデータに対してのみ使うべき

v-show

  • このdirectiveはtransitionのtriggerを発行する
  • バインディングされた値がtrueとして評価される値でない場合はdisplay noneになる
  • それ以外の場合はオリジナルの値

v-class

  • 引数がない場合はバインディングされた値がclassListに追加される
  • 引数が与えられた場合はバインディングされた値によってクラスがtoggleされる
<span v-class="
    red    : hasError,
    bold   : isImportant,
    hidden : isHidden
">

v-attr

  • 引数が必須のdirectiveで、指定された属性の値をセットする
<canvas v-attr="width:w, height:h"></canvas>
  • 属性の内部で{{ Mustache }} 使った場合はv-attrとしてコンパイルされる
  • img srcを指定する場合はMustacheではなくてv-attrで指定すべき
  • そうしないとブラウザが評価した時にMustache形式のままHTTPリクエストを発行して404が起きてしまう

v-style

  • インラインでCSSを指定できる
  • 引数が与えられなかった場合はel.style.cssTextの値がセットされる
  • 引数が与えられた場合はCSSのスタイルとして設定される
<div v-style="
    top: top + 'px',
    left: left + 'px',
    background-color: 'rgb(0,0,' + bg + ')'
">
  • 指定するプロパティを$から始めるとVue.jsが自動的にprefixをつけてくれる

  • $transformと指定するとtransform、webkitTransform、mozTransform、msTransformを付けてくれる

  • IEはHTMLをパースする時にinvalidなstyle指定を削除するのでMustache形式の指定ではなくてv-styleで指定した方がいい

v-on

  • 関数か式を引数で指定する必要がある
  • イベントリスナーを要素に登録する
  • イベントのタイプは引数で指定する
  • key filter(キー入力のfilter)と一緒に使うことが出来る

v-model

  • 編集可能な要素に対して双方向データバインディングを提供する
  • このdirectiveはinputやselectやtextareaなど編集出来る要素でのみ使うことが出来る
  • データは常に同期されるけどlazyオプションを指定した時にはchangeイベントのタイミングで同期される
  • 詳しくはHandling Formsの項目を

v-if

  • このdirectiveは子のViewModelを作る
  • transitionのtriggerを発行する
  • バインディングされた値がtrueな値かどうかによって要素が挿入、削除される
  • 初期値がfalseな値の場合、子のViewModelはtrueになるまで作られない

v-repeat

  • このdirectiveは子のViewModelを作る

  • このdirectiveは配列の値を必要とする

  • transitionのtriggerを発行する

  • バインディングされた配列の各要素毎に子のViewModelを作る

  • 作成された子のViewModelはpushなどの配列を操作するメソッドによって自動的に挿入、削除される

  • 引数が与えられなかった時はViewModelの$dataを配列として扱う

  • この値がオブジェクトてなくて単なる値の場合は$valueとしね参照することが出来る

  • 引数が一つ与えられた場合は、指定されたViewModelのプロパティを対象とする

  • またuser : usersのようにプロパティへのアクセスを明示的にすることも出来る

v-view

  • このdirectiveは子のViewModelを作る
  • transitionのtriggerを発行する
  • 指定された値をComponentIDとして探して構築する
  • 値が変更された時は既にあったViewModelの値は破棄されて新しいViewModelが作成される
  • また、元々のelementも置き換えられるがすべての属性は新しい要素にコピーされる

v-with

  • このdirectiveは子のViewModelを新しく作成する
  • このdirectiveはkeypathのみを受け付ける
  • 親のViewModelのデータから新しくViewModelを作ることが出来る
  • 指定したkeypathのオブジェクトをdata optionで渡しているかのように何も付けずに参照出来る(要するにwith)
  • また親のViewModelとは違う値で参照するようにも出来る
<div v-with="myName : user.name, myEmail: user.email">
    <!-- you can access properties with the new keys -->
    {{myName}} {{myEmail}}
</div>

Literal Directives

  • Literal Directivesはその属性値をただの文字列として扱う
  • bind()メソッドが一度だけ実行される
  • 値にmustache形式で指定することはできるけど評価されるのは一度だけなのでその後に変更しても反映されない

v-component

  • 指定されたComponentを子のViewModelとしてコンパイルする
  • v-withと組み合わせて親のViewModelのデータを使用することも出来る

v-ref

  • v-component、v-with、v-repeatと一緒に使われていないときは無視される
  • 登録すると親のViewModelからv-refで指定したViewModelをvm.$.[v-refで登録した値]で参照できるようになる
  • v-repeatと一緒に使うとそれぞれの要素の子ViewModelと関連付けできるようになる
  • (親からViewModelとして各要素を参照出来るようになるのがメリット?)

v-partial

  • 登録されたpartialで置き換える
  • partialはVue.partial()で登録するか、partialsのオプションで指定出来る
  • {{> partial_name}}の形式でも使うことが出来る

v-effect

  • JavaScriptによるeffectを要素に登録する
  • JavaScriptによるeffectはVue.effect()かeffectsのオプションで指定出来る

Empty Directives

Empty Directivesは属性値を指定しても意味なくて無視される

v-transition

  • CSS Transitionを使用する要素であることをVue.jsに通知する
  • CSS Transtionのtriggerを発行するdirectiveの状態が変化したときや、DOM操作メソッドによってDOMが変化したときにtransitionのクラスが要素に追加される

v-animation

  • CSS Animationを使用する要素であることをVue.jsに通知する

v-pre

  • 指定された要素とその子要素のコンパイルをスキップする
  • directiveが指定されていないたくさん子要素を持っている要素に指定してスキップさせることでコンパイルの速度をあげることが出来る

v-cloak

  • この属性は関連する要素のコンパイルが終わるまでが残り続ける
  • [v-cloak] { display: none } のようなCSSと組み合わせて使うことで、コンパイルが終わっていない{{mustache}}が表示されてしまうのを防ぐことが出来る

#Filters

capitalize

  • 'abc' => 'Abc'

uppercase

  • 'abc' => 'ABC'

lowercase

  • 'ABC' => 'abc'

currency

  • 12345 => $12,345.00

  • 引数で通貨の記号を指定することも出来る

pluralize

  • 引数が一つの時は値が複数であれば引数の文字列にsをつけてくれる
  • 引数で配列を渡すと値によって対応した配列の文字列が使われる
    • val - 1を配列のindexとして使う
  • 値が配列の要素数より大きい場合は最後の値が使われる
<span v-text="date | st nd rd th"></span>
Will result in:
1 => '1 st'
2 => '2 nd' 3 => '3 rd' 4 => '4 th' 5 => '5 th'

key

  • このfilterはv-onとの組み合わせでのみ有効で引数を一つ受け取る
  • 指定したkeycodeにマッチするかでv-onのイベントハンドリングをフィルタすることが出来る
  • keycodeとして下記のようなエイリアスを使うことが出来る
  • enter
  • tab
  • delete
  • esc
  • up
  • down
  • left
  • right
<input v-on="keyup:doSomething | key enter">

filterBy

  • v-repeatとの組み合わせでのみ有効
  • v-repeatで表示するデータを引数で指定したViewModelの値でフィルタリングすることが出来る
  • またin propertyの様に検索するプロパティを指定することも出来る
<input v-model="searchText">
<ul>
    <li v-repeat="users | filterBy searchText in name">{{name}}</li>
</ul>
  • 引数の指定をシングルクォーテーションで囲むことで値を直接指定することも出来る

orderBy

  • v-repeatとの組み合わせでのみ有効
  • v-repeatの結果をソートする
  • 指定するソートのキーはViewModelのコンテキストで評価される
  • reserseKeyとしてpropertyを指定することが出来て、指定されたkeyの値がtrueでない場合は、reserver sortになる
  • sort keyをシングルクォーテーションで囲むことも出来て、reserver sortであることを示すためにreverseKeyに-1を指定することも出来る
<ul>
    <li v-repeat="users | orderBy field reverse">{{name}}</li>
</ul>

Original

http://vuejs.org/guide/


Installation

IE8以下はサポートしない

Getting Started

  • ViewModelにフォーカスしたフレームワーク
  • DOM操作はDirectivesやFiltersをつかう
  • フルスタックなフレームワークではなくて、シンプルで柔軟にデザインされていて、他のライブラリと一緒に使うこともできる
  • firebaseとの組み合わせもよい
  • APIはAngularJS, KnockoutJS, Ractive.js、 Rivets.jsらに影響を受けてる
    • でもこれらよりもシンプル

ViewModel

  • Vueのコンストラクタから作ることが出来てViewとModelのデータをsyncする

View

  • vm.$elで参照出来る。Viewは自動的に更新されるので自分でDirectives作ったりして操作することはあまりない
  • データの更新は非同期で行われるのでパフォーマンスにも優れている

Model

  • ただのJavaScriptのオブジェクト
  • データの更新はES5のsetter getterによってフックされているので使う側は意識しなくてもいい

Directives

  • HTML属性として利用することでDOM操作を隠蔽してくれる

Mustache Bindings

  • テキストや属性の指定でMustacheのBindingを使うことが出来る
  • img srcに指定したりするとtemplateを最初にパースする時に404のHTTPリクエストが発生してしまうのでv-attrで指定する
  • IEの場合styleにinvalidな属性を指定していると削除されるのでサポートするならv-styleで指定する

Filters

  • Viewに表示される前にpipeされてくる

Components

  • IDによって管理されるシンプルなViewModelのcostructor
  • v-componentsとしてテンプレートで指定できる
  • web componentsのように再利用性のあるもの

Directives In Depth

Synopsis

  • angular.jsのDirectivesよりもシンプルでHTML属性としての埋め込みのみサポートしている

A Simple Example

  • v-xxx の形で定義される。v-textの場合はDOMのtext contentが更新されるとViewModelの値も更新される

Inline Expressions

  • 値には評価式を書くことが出来て、式が依存している値も自動的に追跡して更新される
  • 非同期バッチで更新されて依存している複数の値が更新されても反映はイベントループ毎に一度にまとめて行われる
  • templateにロジックを埋め込みすぎるのは避けるべきでvue.jsでは複数の式を書くことはできない
    • 代わりにComputed Propertiesを使うといい
  • セキュリティ的な理由で式からはcurrentのViewModelとその親のPropertyとMethodしか参照することが出来ない

Arguments

  • 引数も指定できる

Filters

  • |でつなぐことでDOMが更新される前にフックさせる処理を書くことが出来る

Multiple Clauses

  • 1つのDirectiveに対してオブジェクト形式で複数のバインディングを定義することができる

Literal Directives

  • v-componentのようにデータバインディングでなくてリテラルを指定するものもある
  • v0.10からリテラルにMustacheでの指定が出来るようになった
  • しかしながらこれは最初に一度評価されるだけなので動的にしたい場合はv-viewを使うといい

Empty Directives

  • v-preのように属性値を指定しないものもある

Writing a Custom Directive

  • Vue.directiveを使ってカスタムDirectiveを作ることも出来る
  • directive idと最初に一度呼ばれるbind、バインディングされてる値が更新される度に呼ばれるupdate、最後に一度だけ呼ばれるunbindを必要に応じて実装する
  • updateだけ指定する時は第二引数に関数を直接指定することができる
  • 定義した関数は中でthisから呼び出すことが出来て、thisには他にもel key args Expression vm valueなどが使えるようになっている
<div id="demo" v-demo="LightSlateGray : msg"></div>
Vue.directive('demo', {
    bind: function () {
        this.el.style.color = '#fff'
        this.el.style.backgroundColor = this.arg
    },
    update: function (value) {
        this.el.innerHTML =
            'argument - ' + this.arg + '<br>' +
            'key - ' + this.key + '<br>' +
            'value - ' + value
    }
})
var demo = new Vue({
    el: '#demo',
    data: {
        msg: 'hello!'
    }
})
argument - LightSlateGray
key - msg
value - hello!
  • これらの値はreadonlyとして扱うべきで、オブジェクトにはプロパティを追加することもできるけど内部的な値を上書きしないように注意する必要がある

Creating Literal & Empty Directives

  • isLiteralかisEmptyをtrueにするとデータバインディングされずにbindとunbindだけが有効になる
  • isLiteralの場合はExpressions key argが使えて、isEmptyでは何も渡されない

Creating a Function Directive

  • Vue.jsではデータと振る舞いを分けることを推奨していてdataの中にメソッドはない
  • Directiveの中でメソッドを使いたい場合はisFnをtrueに指定する

Filters in Depth

Synopsis

  • filterは|で定義することが出来て、値を処理して新しい値を返すことが出来る
  • filterは引数を取ることも出来る

Examples

  • directiveの最後に指定したり、Mustacheバインディングで定義したり、filterをパイプでつないだり出来る
<span v-text="message | capitalize"></span>
<span>{{message | uppercase}}</span>
<span>{{message | lowercase | reverse}}</span>

Arguments

  • 引数を取ることが出来るfilterはスペース区切りで引数を指定する

Writing a Custom Filter

  • カスタムfilterはVue.filter()で作ることが出来て第一引数にfilterIdを、第二引数に実装を書く
  • 実装する関数は第一引数にfilterの対象が渡されて、第二引数以降にfilterに渡された引数があれば渡される
Vue.filter('wrap', function (value, begin, end) {
    return begin + value + end
})

Computed Filters

  • filterの中でのcontextはfilterが定義されている要素のViewModelになっていて、ViewModelの状態によって動的に結果が変化する
  • ViewModelとViewModelを参照しているfilterはComputed filtersとして結びつけられる
  • Computed filtersがどのように動作してるのかわからなくてもVue.jsがいい感じにやってくれるので問題ない

Displaying a List

  • v-repeatでObjectやArrayの要素をViewModelとしてtemplateで繰り返し出力することができる
  • 繰り返し処理の中では子要素だけでなく親要素も参照することが出来る
  • 加えて$indexでindexの参照も出来る

Arrays of Primitive Values

  • 配列の要素がprimitiveな値の場合は、$thisで参照することが出来る

Using an identifier

  • 親要素を参照する場合など、子要素への参照をv-repeat="user: users"のようにして明示的にすることも出来る

Mutation Methods

  • vue.jsではArrayのpush、pop、shift、unshift、splice、sort、reverseをフックしてviewへ更新が反映される
  • 配列に対してindexでの参照で更新するのはvue.jsで追跡されないので避けるべき
  • そういった場合は$setや$removeを使うといい

$set( index, value )

  • 配列の指定したindexの要素を更新する

$remove( index | value )

  • spliceのsyntax sugarで指定した要素を削除する

Setting a new Array

  • filterなどnon-mutatingな新しい配列を返すようなメソッドの場合、全てのDOMが作り直されると思うかもしれないけど、Vue.jsは賢いから可能な限り再利用される

##Array Filters

  • 実際のデータではなくて、表示上でfilterしたりsortしたい場合はfilterByやorderByといった標準のfilterを使うといい

Iterating Through An Object

  • v0.8.8からオブジェクトのpropertyをv-repeatで繰り返し処理出来るようになった
  • $keyでkeyが参照できて、値がprimitiveの場合は$valueで、オブジェクトの場合はcontextに設定されるのでそのまま参照できる

$add() and $delete()

  • ECMAScript 5ではpropertyの追加・削除をフックすることが出来ないので、$add, $deleteを使って行うことでviewも更新される

Listening for Events

  • v-onのdirectiveでDOMイベントを購読することが出来る
  • 関数名を書くか式を書くことも出来る
  • 関数名を書く場合は引数にDOMのイベントオブジェクトが渡される
  • またtargetVMというプロパティでイベントが発行されたViewModelを参照することも出来る

Invoke Handler with Expression

  • targetVMはv-repeatの中で使うと便利
  • また定義する式の中でthisとしてViewModelを参照することも出来るのでその方がより使いやすいかも
  • DOMイベントは定義する式の中で$eventとして参照することも出来る

The Special key Filter

  • keyboard入力を購読する時用にv-onでだけkeyというfilterを使うことが出来る
  • key | 13のような形でも使ったりkey | enterのように使ったり出来る

Why Listeners in HTML?

  • HTMLにイベントリスナーを定義するのは関心の分離に違反してると思うかもしれないけど、vue.jsのイベントハンドラは対象のViewに紐づいているViewModelによって処理されるのでメンテナンス性は下がらない

  • ちょっと何言ってるわからないみたいな役になってる...

  • また次のようなメリットもある

  1. JSの中に書くよりtemplateに書いた方がシンプルに定義出来る
  2. JS内でイベント購読する処理を書かなくてよくなるので、DOMから解放されてロジックだけを書くことが出来てテストしやすくなる
  3. ViewModelが破棄された時に全てのイベントリスナーも解除されるのでクリーンアップを考える必要がない

Handling Forms

  • v-modelを使うことでFormのような編集可能な2wayバインディングを作ることが出来る

Computed Properties

  • vue.jsのinline expressionsは便利だけど単純なbooleanや文字列結合以上のことをしたい場合はComputed Propertiyを使うべき
  • Computed Propertyはcomputedオプションで定義出来る
  • オブジェクトとして$get $setとしてゲッターセッターを定義する
  • $getだけの場合はオブジェクトの値に直接実装することが出来る
  • Computed Propertyは通常のプロパティと同じように扱うことが出来る
var demo = new Vue({
    data: {
        firstName: 'Foo',
        lastName: 'Bar'
    },
    computed: {
        fullName: {
            // the getter should return the desired value
            $get: function () {
                return this.firstName + ' ' + this.lastName
            },
            // the setter is optional
            $set: function (newValue) {
                var names = newValue.split(' ')
                this.firstName = names[0]
                this.lastName = names[names.length - 1]
            }
        }
    }
})
demo.fullName // 'Foo Bar'

Dependency Collection Gotcha

  • inline expressionsようにComputed Propertyの依存関係も収集してくれる
  • 依存関係の収集は$getで参照されたときに行われるので、条件分岐などで到達しないプロパティに対しては収集されないので条件に関係なく参照されるようにする必要がある
status: function () {
    // access dependencies explicitly
    this.okMsg
    this.errMsg
    return this.validated
        ? this.okMsg
        : this.errMsg
}
  • inline expressionsの場合はvue.jsがやってくれるので任せておけばいい

Adding Transition Effects

  • vue.jsで要素が追加、削除されたときにアニメーションさせるためのフックポイントが用意されている
  • アニメーションはcss transitions、css animations、javascriptによるアニメーションの3つの選択肢がある
  • アニメーションのtriggerはv-ifやvm.$appendToなどvue.js経由でDOM操作が行われた時だけ発行される

CSS Transitions

  • css transitionsを使いたい場合は要素にv-transitionを指定する

  • v-transitionを指定した要素に要素が追加された時にはv-enter、削除された時にはv-leaveというclassが追加されるようになるのでそれを使ってアニメーションを記述する

  • v-enterといった名前はVue.config()で変更できる

  • 要素が非表示になるとき

  1. 要素のclassにv-leaveが追加される
  2. transitionendイベントが発行されるまで待つ
  3. 要素を削除してv-leaveも削除する
  • 要素が表示されるとき
  1. 要素のclassにv-enterが追加される
  2. 要素がDOMに挿入される
  3. v-enterが追加されることでレイアウトが更新される
  4. v-enterが削除されて元の状態に戻る

transitionendイベントで状態が更新されるので、transitionendが発行されない場合は処理がされないので注意

CSS Animations

  • css animationsはtransitionsと似た方式を提供しているけどv-animationを使う
  • 違いとしてはv-enterのクラスがDOMが挿入された後に即時に削除されずにanimationendのcallbackを待つ(???間違ってるかも)

JavaScript Functions

  • vue.jsは要素の追加、削除時に任意の関数を呼ぶことが出来る
  • そのためにはVue.effectで関数を登録してアニメーションさせたい要素にv-effectで作成したeffectを指定する
Vue.effect('my-effect', {
    enter: function (el, insert, timeout) {
        // insert() will actually insert the element
    },
    leave: function (el, remove, timeout) {
        // remove() will actually remove the element
    }
})

Composing Components

Registering a Component

  • vue.jsではViewModelをweb componentsのように再利用性のあるものとして扱うことができる(polyfillなしで)
  • componentを使うためにはまずVue.extendでコンストラクタを作って、それをVue.componentを使って登録する
  • またVue.componentにプロパティをオブジェクトとして渡すことで直接作ることも出来る
// Extend Vue to get a reusable constructor
var MyComponent = Vue.extend({
    template: 'A custom component!'
})
// Register the constructor with id: my-component
Vue.component('my-component', MyComponent)
Vue.component('my-component', {
    template: 'A custom component!'
})
  • するとcomponentを定義したViewModelのテンプレートの中で使うことが出来るようになる
  • componentはtop levelのViewModelがインスタンス化される前に登録される
<div v-component="my-component"></div>

だけでなくカスタム要素として定義することも出来る

<my-component></my-component>
  • カスタム要素名で定義するときはnativeで定義されているものと衝突しないように注意する

  • そのためには要素名にハイフンを含める必要がある

  • Vue.extendとVue.componentの違いを理解することは重要

  • VueはコンストラクタでVue.extendは継承のためのメソッドでVueのサブクラスのコンストラクタを返す

  • Vue.componentはVue.directiveのような登録を行うためのメソッド

  • String IDとコンストラクタを渡すことでテンプレートから使うことが出来るようになる

  • Vue.componentに直接オプションのオブジェクトを渡したときは裏でVue.extendが呼ばれている

  • Vue.jsはBackboneのようなクラスによる継承ベースな仕組みとdirectiveのようなweb componentsのスタイルをサポートしている

  • 混乱するかもしれないけどとnew Image()の二通り、画像の要素の作り方があるようなもの

  • どちらも便利なのでVue.jsではどちらもサポートすることで柔軟性を高めようとしている

Data Inheritance

Inheriting Objects from Parent as $data

  • v-withを使うことで親要素のデータを継承することが出来る
<div id="demo-1">
    <p v-component="user-profile" v-with="user"></p>
</div>
// registering the component first
Vue.component('user-profile', {
    template: '{{name}}<br>{{email}}'
})
// the `user` object will be passed to the child
// component as its $data
var parent = new Vue({
    el: '#demo-1',
    data: {
        user: {
            name: 'Foo Bar',
            email: '[email protected]'
        }
    }
})

Inheriting Individual Properties with v-with

  • v-withに引数が与えられたとき、子のcomponentの$dataに追加される
  • その場合親の要素とsyncし続ける
<div id="parent">
    <p>{{parentMsg}}</p>
    <p v-component="child" v-with="childMsg : parentMsg">
        <!-- essentially means "bind `parentMsg` on me as `childMsg`" -->
    </p>
</div>
new Vue({
    el: '#parent',
    data: {
        parentMsg: 'Shared message'
    },
    components: {
        child: {
            template: '<input v-model="childMsg">'
        }
    }
})

Using v-component with v-repeat

  • 配列のデータに対してはv-repeatとv-componentを組み合わせることができる
<ul id="demo-2">
    <!-- reusing the user-profile component we registered before -->
    <li v-repeat="users" v-component="user-profile"></li>
</ul>
var parent2 = new Vue({
    el: '#demo-2',
    data: {
        users: [
            {
                name: 'Chuck Norris',
                email: '[email protected]'
            },
            {
                name: 'Bruce Lee',
                email: '[email protected]'
            }
        ]
    }
})

Accessing Child Components

  • 時々、javascriptの中で子のcomponentのデータにアクセスしたくなることがあるかもしれない
  • その場合、子のcomponentにv-refで参照するためのIDを書いておくとparent.$.xxuの形式で参照することが出来る
<div id="parent">
    <div v-component="user-profile" v-ref="profile"></div>
</div>
var parent = new Vue({ el: '#parent' })
// access child component
var child = parent.$.profile

Event Communication Between Nested Components

  • ViewModelは親子間で直接アクセスすることが出来るけど、異なるComponent間でのやりとりにはVue.jsのイベントを使ったほうがいい
  • そうすることでメンテナンス性とコードを減らすことが出来る
  • 一度ViewModelの親子関係が確立すると、$dispatchや$onなどのViewModelのイベント関連のメソッドでやりとりが出来る

Encapsulating Private Assets

  • 時々Componentをどこでも再利用できるようにカプセル化したくなることがあるかもしれない
  • そういったときはインスタンスのオプションで指定することで、そのViewModelのインスタンスか子のComponentでしかアクセス出来ない値を作ることが出来る
// All 5 types of assets
var MyComponent = Vue.extend({
    directives: {
        // id : definition pairs same with the global methods
        'private-directive': function () {
            // ...
        }
    },
    filters: {
        // ...
    },
    components: {
        // ...
    },
    partials: {
        // ...
    },
    effects: {
        // ...
    }
})
MyComponent
    .directive('...', {})
    .filter('...', function () {})
    .component('...', {})

Content Insertion Points

Single insertion point

  • 再利用性のあるComponentを作るとき、Component内の要素を使いたいことがある
  • Vue.jsはWebComponentsのドラフト仕様と互換性のある要素を挿入する仕組みを持っていて、content要素をComponent内に挿入する場所として定義する
  • 属性なしのcontent要素が1つだけ定義されている場合は、そこがComponent内の要素と置換される
  • content要素内にはfallback要素を定義することが出来て、挿入する対象がない場合に使用される
<h1>This is my component!</h1>
<content>This will only be displayed if no content is inserted</content>
<div v-component="my-component">
    <p>This is some original content</p>
    <p>This is some more original content</p>
</div>
<div>
    <h1>This is my component!</h1>
    <p>This is some original content</p>
    <p>This is some more original content</p>
</div>

Multiple insertion points and the select attribute

  • content要素はselect属性を持つことが出来て、css selectorを指定することが出来る
  • 複数のcontent要素を指定する場合は、select属性にそってどのcontentを置換するか指定することが出来る
<content select="p:nth-child(3)"></content>
<content select="p:nth-child(2)"></content>
<content select="p:nth-child(1)"></content>
<div v-component="multi-insertion-component">
    <p>One</p>
    <p>Two</p>
    <p>Three</p>
</div>
<div>
    <p>Three</p>
    <p>Two</p>
    <p>One</p>
</div>

Building Larger Apps

  • Vue.jsは可能な限り柔軟に設計されている
  • ただのライブラリで他のアーキテクチャと衝突しないように
  • プロトタイプを素早く作るときに便利
  • 大規模なアプリケーションをVue.jsを使って作ろうと思うかもしれないのでここではその方法について説明する

Build with Component

  • Vue.jsはComponentというフロントエンドのパッケージマネージャー&ビルドツールを使って構築されている

  • Compomentを使うとブラウザでもCommonJSスタイルで書くことが出来て、Githubにpushすることで簡単にモジュールを公開することが出来る

  • サンプルはこちら https://github.com/vuejs/vue-component-example

  • すでに下記にたくさんのComponentが公開されているので、フロントエンド開発の一般的な問題に対しては役に立つ

  • https://github.com/component/component/wiki/Components

  • 大規模なアプリケーションを作るときは、Vue.jsをインターフェイスとして、足りない機能をComponentで公開されているライブラリを使う形になる

  • また、Browserifyという素晴らしいビルドライブラリもあって、こちらはGithubではなくてnpmを使っていてコミュニティも盛り上がっている

  • http://browserify.org/

Modularization

  • ComponentはJavaScriptのビルドだけでなくCSSやTemplateなどのassetのビルドも出来る
  • またビルドをフックすることでCoffeeScriptやSassやStylusを使う事もできる
  • その結果、JavaScriptとCSSとHTMLをカプセル化してCompomentとして扱うことが可能になる
  • https://github.com/vuejs/vue-component-example
  • 似たようなことはBrowserifyでもpartialifyのようなtransformのpluginを使うことで可能
  • https://github.com/vuejs/vue-browserify-example

Routing

  • 基本的なRoutingはhashchangeイベントとv-view directiveを使って実装することが出来る
  • v-view directiveはcomponentを動的にロードするのに効果的
  • componentのIDをバインドすることで新しいViewModelのインスタンスが生成されて、古いViewModelは削除される
<div id="app">
    <div v-view="currentView"></div>
</div>
Vue.component('home', { /* ... */ })
Vue.component('page1', { /* ... */ })

var app = new Vue({
    el: '#app',
    data: {
        currentView: 'home'
    }
})
  • v-viewは要素を新しいViewModelで置換するので、rootの要素で指定するのは避けたほうがいい
  • v-viewは Page.jsDirectorといったライブラリと簡単に組み合わせることが出来る
  • また、Routingを簡単に出来るvue-routerを提供する予定もある

Communication with Server

  • ViewModelはJSON.stringifyでシリアライズされた$dataを持っている
  • ajaxのcomponentはSuperAgentのような好みのものをつかう事が出来る
  • またFirebaseのようなサービスをバックエンドにすることも出来る
  • またAngular.jsの$resourceのようなREST APIのクライアントもvue-resourceとして提供する予定

Unit Testing

  • Componentを使うと、ViewModelやdirectiveやfilterをCommonJSのモジュールとして分割することが出来る
  • Componentベースのプロジェクトはstandalone flagが立ってrequireメソッドがexportされて、内部モジュールにアクセスすることが出来る
  • これによってテストとテスト対象を含んだビルドを作ってブラウザでのユニットテストが簡単にできるようになる
  • ベストプラクティスはメソッドが含まれた生のオブジェクトをexportすること
// my-component.js
module.exports = {
    created: function () {
        this.message = 'hello!'
    }
}
// main.js
var Vue = require('vue')

var app = new Vue({
    el: '#app',
    data: { /* ... */ },
    components: {
        'my-component': require('./my-component')
    }
})
// Some Mocha tests
// using a non-standalone build of the project
describe('my-component', function () {
    
    // require exposed internal module
    var myComponent = require('my-project/src/my-component')
    it('should have a created hook', function () {
        assert.equal(typeof myComponent.created, 'function')
    })
    it('should set message in the created hook', function () {
        var mock = {}
        myComponent.created.call(mock)
        assert.equal(mock.message, 'hello!')
    })
})
  • Vue.jsのバインディングは非同期に行なわれるので、更新後のDOMの値を確認するときはVue.nextTick()を使う必要がある

Plugins

これはpreview版なのでAPIなどに変更があるかもしれない

  • こんな感じで使う
// assuming using a CommonJS build system
var vueTouch = require('vue-touch')
// use the plugin globally
Vue.use(vueTouch)

// Extended components can use plugins too!
var awesomePlugin = require('vue-awesome'),
    MyComponent = Vue.extend({})
MyComponent.use(awesomePlugin)

// arguments
Vue.use('vue-touch', { moveTolerance: 12 })
  • Componentだと↓のような使い方も出来る
// will auto require('vue-touch')
Vue.use('vue-touch')

Plugin Implementation

  • 渡されるVueのコンストラクタはVueを継承したComponentかもしれない
  • 中ではVue.requreとメソッドの登録だけが出来る。Vue.configをPluginの中でVue.configを使用してはいけない
exports.install = function (Vue, options) {
    // use Vue.require to access internal modules
    var utils = Vue.require('utils')
}
@yyx990803
Copy link

Wow, good job! Thanks for putting in the effort to translate all these :)
どうもありがとうございました!

@koba04
Copy link
Author

koba04 commented Apr 17, 2014

My pleasure! Thanks for good library and documentation! 😆

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment