Vue.js(2)コンポーネント

Vueコンポーネント

Vue.jsでは、名前付き再利用可能なVueインスタンスとして、Vueコンポーネントという仕組みが用意されており、HTMLの要素やスタイル、状態、挙動などを使いまわせる部品としてまとめて定義できる。Vue.component()という関数が用意されており、第一引数にVueインスタンス内に存在する要素名=コンポーネント名)を、第二引数にオプションを与える。

コンポーネント名は、kebab caseでもcamel caseでもどちらで命名しても構わないが、DOM内ではkebab caseでしか記述できないことを考慮すると、kebab caseに統一しておくことが望ましい。

<ul id="app">
  <list-item></list-item>
  <list-item></list-item>
  <list-item></list-item>
</ul>

<script>
Vue.component('list-item',{
  template: '<li>item</li>'
})
new Vue({
  el: '#app'
})
</script>

Vueコンポーネントで指定できるオプションは、以下の通り。

名前 内容
data UIの状態とデータ
filters データの整形
methods イベント時の挙動
computed データから派生して算出する値
template コンポーネントのテンプレート
props 親要素から子要素へのデータ受け渡し

コンポーネントは、グローバルのVue.jsに対して定義するグローバルコンポーネントと、あるVueインスタンスの中のみで使用できるローカルコンポーネントが存在する。ローカルコンポーネントは、対象のVueインスタンス内で定義する。

コンポーネントテンプレート

text/x-template

template内の要素をscriptタグ内で定義する方法

<script type="text/x-template" id="list-item">
  <li>item</li>
</script>

renderオプション

コンポーネント内でコードを用いる場合は、renderオプションを使用する。

単一ファイルコンポーネント

.vue拡張子の単一ファイル上でコンポーネントを実装することができる。これらのファイルを利用するときは、Webpackなどによるプリコンパイルが必要となる。また、Vueインスタンス内のcomponentsオプションにて、利用するコンポーネントを指定する必要がある。

下記のように、単一ファイルコンポーネント内でも他のコンポーネントをローカル登録することが可能である。

import ComponentA from './ComponentA'

export default {
  components: {
    ComponentA
  }
}

コンポーネントデータ

コンポーネント内のdataオブジェクトにそのままデータを記載すると、コンポーネントの全てのインスタンスでこれらのデータが共有されてしまう。これを防ぐために、コンポーネントでdataオブジェクトを使用する際には、関数を用いて値を返却する実装とする

コンポーネント間の通信

Vue.jsでは、各コンポーネント内で独自のスコープを持つので、基本的にはコンポーネントを跨いだデータの受け渡しはできないが、親コンポーネントと子コンポーネントの間では、データの受け渡しが可能である。親から子へはpropsオプションを用いて子から親にはイベントを用いてデータを受け渡す。

propsオプションは子コンポーネント内に記載し、受け渡されるデータの属性名や型などを指定することができる。親コンポーネントでは、v-bindを用いて受け渡す値を指定する。

コンポーネント 値の指定方法 値の命名規則
親コンポーネント v-bind:受け渡す値の名前=’コンポーネント内の値の名称’ kebab case
子コンポーネント props: {受け取る値の名前: {}} camel case

子コンポーネントから親コンポーネントへの通信は、カスタムイベントを使用する。イベントのリッスンには $on(eventName) を、イベントトリガには、 $emit(eventName) を使用する。

Vue.js(1)Vue.jsの概要

Vue.jsの特徴

Vue.jsは、ビューだけを取り扱うシンプルなライブラリで、DOM要素にバインディング指定することで、データ変更を検出する度に、DOM要素が表示内容を自動で更新する「リアクティブなデータバインディング」を提供する。したがって、値を都度算出したり、その値を設定するコードが不要。また反対に、ユーザからの入力を検出する度にJavascriptのデータを更新することもできる。

Vue.jsは、フレームワークはどんな規模でも段階的に柔軟に使えるべきであるという、ブログレッシブフレームワークの思想を基に開発されており、ライブラリを導入するなどすることで、規模や要求に応じた対応が可能である。

またVue.jsは、HTMLライク(HTML, CSS, Javascript)なコンポーネント単一ファイルに記述できるために非常に学習コストが低い。

Vue.jsの基本

Vue.jsは、イベントと要素との間に状態(State)を持つために、イベントとDOMとの関係を分けて考えることが可能である。UIの状態を担うJavascriptオブジェクトを中心に据え、

  • UIの状態とJavascriptオブジェクト
  • UIの状態とDOMツリー
  • イベントと状態の変更

の3つの視点からコンテンツを制作できる。

Vue.jsの構成

Vueオブジェクト

グローバル変数Vueは、コンストラクタモジュールの2つの役割を持つ。コンストラクタに指定する オプションオブジェクト は、以下のプロパティを指定することができる。

名前 内容
data UIの状態とデータ
el Vueインスタンスをマウントする要素
filters データの整形
methods イベント時の挙動
computed データから派生して算出する値

elプロパティ もしくは mountメソッド を用いて、マウント対象の要素を指定する。Vueの影響範囲は、このマウントした要素とその子要素に限られる

var vm = new Vue({
  el: '#app'
})
var vm = new Vue({
})
vm.$mount('#app')

また、これらのプロパティにアクセスするためのインスタンスプロパティが用意されている。詳細は、vue インスタンスプロパティを参照のこと。

インスタンスプロパティの例 内容
vm.$data データオブジェクト
vm.$props プロパティオブジェクト
vm.$el ルートDOM

UIデータの定義

dataプロパティを用いて、データのオブジェクトを指定する。dataプロパティで規定したデータは、更新毎に表示も変化する。この値をHTML上に反映させるためには以下のように記述する。なお、Vueインスタンスの変数名は、ViewModelの略として、慣例的にvmをよく使用する。

var vm = new Vue({
  el: '#app'
  data: {
    key: 'value'
  }
})
<div id="app">
  <p>{{ key }}</p>x
</div>

なお、 {{ key }} は、データをHTMLではなくプレーンテキストとして扱うため、HTMLとして出力する必要がある場合には、 v-html ディレクティブを使用する。また、dataプロパティにはデータのみを置き、値の処理を行う関数などは、methodsプロパティcomputedプロパティに記載する。

$watchメソッドは、Vueインスタンスの変更を検知し動作を開始するため、デバッグ等に利用できる。第一引数に監視対象の値第二引数に値が変更した際に事項する処理内容を規定します。

vm.$watch(function(){
  return this.key
},function(){
}

テンプレート

Vue.jsは、データとDOMツリーの関係を定義するテンプレート機能を提供しており、Mustache記法によるデータ展開ディレクティブによるHTML要素の拡張を行うことができる。dataプロパティのデータ だけでなく、 Computed, Method, Filterで定義した関数名 を指定することができる。

詳細は、テンプレート構文 – Vue.jsを参照のこと。

データ展開

v-bindを利用して、属性プロパティに値を適用することができる。

v-bind:属性名="dataのkey"

文字列だけではなく真偽値を適用して、表示を変更することもできる。また、属性名を角括弧で囲うことで、属性名を変数名として定義することもできる

<div id="app">
  <button v-bind:[attribuiteName]="key">button</button>
</div>
<script>
var attributeName = 'title'
var vm = new Vue({
  el: '#app',
  data: {
    key: 'value'
  }
})
</script>

v-bind:class に配列を渡すこともできる。

<div v-vind:class="[activClass, errorClass"]></div>

フィルタ

filtersプロパティは、テキストのフォーマット処理を行うことができる。関数として定義し、関数名がフィルタ処理後の変数名となる。{{ 値|フィルタ名 }}と記述することで、指定した値にフィルタを適用できる。

<div id="app">
  <p>{{ filteredKey|keyFilter }}</>
</div>
<script>
var vm = new Vue({
  el: '#app',
  data: {
    key: 'value'
  },
  filters: {
    keyFilter: function(){
    }
  }
})
</script>

複数のフィルタを | で連結することもできる。

算出プロパティ

computedプロパティは、派生したデータをプロパティとして公開する仕組みで、データに処理を加えたいときに使用する。 this を用いることで、 Vueインスタンス内の各種プロパティにアクセス できる。

詳細は、算出プロパティとウォッチャ – Vue.jsを参照のこと。

<div id="app">
  <p>{{ computedValue }}</>
</div>
<script>
var vm = new Vue({
  el: '#app',
  data: {
    key: 'value'
  },
  computed: {
    computedValue: function(){
        return this.key+100
    }
  }
})
</script>

算出プロパティも依存しちえるデータが更新されれば、自動的に更新される。算出プロパティは、算出対象の変数などの依存関係が更新されたときのみ再実行されるのに対して、メソッドは、再描画が発生する度に実行される

算出プロパティは、通常getterのみ提供されているが、別途setterを定義することもできる。

ディレクティブ

HTMLに対してディレクティブと呼ばれる独自の属性を追加し、DOMの操作を行うことができる。

条件付きレンダリング

v-ifおよびv-showディレクティブを用いて、これらの属性に真偽値を適用することで、要素の表示非表示を制御することができる。v-ifはDOMの追加削除自体を行うが、v-showはdisplayプロパティの変更を行って表示非表示を行う。頻繁に表示非表示が変更される場合は、v-showを使うほうがレンダリングコストが低い。

v-ifディレクティブと同時に、v-else-ifディレクティブv-elseディレクティブを使用することもできる。これらのディレクティブを使用した場合、再利用が可能な要素は描画されずにそのまま利用される。明示的に再描画を行う場合には、Key属性を追加して、Vueに別要素として認識させる必要がある

データ変更時の更新は行わずに展開を1度のみ行う場合は、v-onceディレクティブを使用することもできる。

詳細は、条件付きレンダリング – Vue.jsを参照のこと。

<div id="app">
  <p v-if="isShown">text</>
</div>
<script>
var vm = new Vue({
  el: '#app',
  computed: {
    isShown: function(){
        return true;
    }
  }
})
</script>

クラスとスタイルのバインディング

特定の条件を満たしているときにUIを変更する場合は、v-bindディレクティブを使用する。

また、v-bind:classは、指定された値のうち真のプロパティのみ、Classの属性値に反映する。下の例では、isShownは真のときのみ、error属性がClass属性に反映する。

<div id="app">
  <p v-bind:class="(error: isShown)">text</>
</div>
<script>
var vm = new Vue({
  el: '#app',
  computed: {
    isShown: function(){
        return true;
    }
  }
})
</script>

v-bind:styleは、スタイルプロパティとして要素に反映される。v-bind:属性名は、:属性名と省略して記述することもできる。

詳細は、クラスとスタイルのバインディング – Vue.jsを参照のこと。

リストレンダリング

v-forディレクティブを用いることで、配列もしくはオブジェクトデータを繰り返して表示できる。v-forは、v-bindと共に使用して、v-bindで一意なキーを与えなければならない

v-for="要素 in 配列"

また、v-forディレクティブは、オブジェクトのプロパティに対しても使用することができる。このとき、オブジェクトの値(Value)だけでなく、キー(key)およびインデックス(index)を指定することもできる

<ul id="v-for-object" class="demo">
  <div v-for="(value, name, index) in object">
    {{ index }}. {{ name }}: {{ value }}
  </div>
</ul>
new Vue({
  el: '#v-for-object',
  data: {
    object: {
      title: 'How to do lists in Vue',
      author: 'Jane Doe',
      publishedAt: '2016-04-10'
    }
  }
})

リスト要素に対する画面更新を行うために、push(), pop(), shift(), unshift(), splice(), sort(), reverse()などの変更メソッドがあらかじめ用意されている。

詳細は、リストレンダリング – Vue.jsを参照のこと。

イベントハンドリング

v-onディレクティブを持ちることで、イベントの発生の検知と検知時の実行する動作を記述することができる。v-on:イベント名は、@イベント名と省略して記述することもできる。

v-on:イベント名="式として実行したい属性名"

また、v-onディレクティブとv-bindディレクティブを、v-modelディレクティブとして記述することもできる。これは、DOMで変更があった場合に、その値をVueに反映できるディレクティブである。

<div id="app">
  <input type="number" v-model="key">
</div>
<script>
var vm = new Vue({
  el: '#app',
  data: {
    key: 'value'
  }
})
</script>

詳細は、イベントハンドリング – Vue.jsを参照のこと。

ライフサイクルフック

Vueにはライフサイクルが規定されていて、それぞれの状態に変化した際に、ライフサイクルフックを用いて処理を実行することができる。

  • beforeCreate
  • created
  • beforeMount
  • mounted
  • beforeUpdate
  • updated
  • beforeDestroy
  • destroy

詳細は、ライフサイクルダイアグラム – Vue.jsを参照のこと。

メソッド

methodsディレクティブを用いることで、Vue内のメソッドを定義することができる。v-onディレクティブにメソッド名を指定して、ボタンクリック等のイベント時に処理をするなどが考えられる。メソッド等を定義する際に記述する function(){ は省略できる

イベント修飾子

メソッドには、 呼び出し元からeventオブジェクトが渡される。eventオブジェクトが持つ preventDefault()stopPropagation() を用いることで、イベントを停止したりイベントの伝搬を停止することができる。

ただし、これらのメソッドを使用することで複雑な処理となることを避けるために、イベント修飾子を提供している。

イベント修飾子 動作
.stop イベントの伝搬を停止する
.prevent ページリロードの停止
.capture
.self event.targetが自分自身の場合のみ呼び出し
.once
.passive

キー修飾子

キーボードイベントをサブスクライブするにあたって、処理を容易にするために、キー修飾子も用意されている。

詳細は、イベントハンドリング – Vue.jsを参照のこと。