Vue.js、JavaScript フレームワークを初めて使う方に向けて、今回はキモとなる Component について解説します

Component の概念から説明していますので、初心者の方にも読みやすい内容です。

結論

  • Component は使いまわし可能なパーツで、メンテナンス性と再利用性を高める
  • 親子間のデータ受け渡しは Binding で実現する
  • 単方向バインディング (v-bind / v-on) と双方向バインディング (v-bind + v-on / sync) を使い分ける

Component とは?

Vue.js や Angular には Component という概念があります。

Component を使用して Vue.js などはコードの共通化を高めています。共通化を行うとメンテナンス性の向上やコード量の削減ができます。

どんなプロジェクトでも必ず Component は使用するので、Vue.js を理解するのには必須です

使いまわし可能なパーツ

Component は簡単に説明すると使いまわし可能なパーツです。

vue ファイルの中で他の vue ファイルを呼び出して使用することができます。

例えばボタンを使いまわし可能な状態で実装すれば、呼び出すだけで同じデザイン、同じ処理を呼び出し側で実装できます。

例:ボタン

実現したいこと: 幅と高さが 20px の「ここをクリック」と表示されたボタンを使いまわしたい。

実装方法:

  1. A ファイルで幅と高さが 20px の「ここをクリック」と表示されたボタンを作成。
  2. B ファイルでボタン Component を呼び出す。

結果: B ファイルでボタンが表示される。

この呼ばれた側 (A ファイル)、呼び出し側 (B ファイル) は親と子で呼ぶことが多いです。

以下からは

  • 呼び出し側 = 親
  • 呼ばれた側 = 子

で説明していきます。

Binding とは?

上記の説明だと、ボタンの場合は次のような不満点があります。

  • ボタンのテキストが固定
  • クリック後の処理を子で書く必要がある

Binding はその不満点を解消する機能です。

Component 間のデータ受け渡し機能

Binding は簡単に説明すると Component 間のデータ受け渡し機能です。

Binding を行うと

  • 親で子のテキストを変更可能にする
  • 子でイベントトリガーを親に引き継ぐ

などができます。結果的に上記で起きていた不満点は、Binding を行うと解決します。


これらの Binding は親と子の関係性が重要で、

  • 親から子、子から親の一方通行な Binding は一般的に単方向バインディング
  • 親と子の双方向な Binding は一般的に双方向バインディング

と呼びます。

Binding の概念が理解できないと Component は上手く扱えないので頑張りましょう。

実際の使用例

ここからは実際に Vue.js のコードを見ながら実装方法を解説します。

vue ファイルの基本については以下の記事で解説していますので、わからない方は参考にしてください。

Component の使用

まずはベースとなる Component の呼び出しを解説します。

上記の例の Binding をしていないボタンの実装方法です。

子で string 文字列を表示する vue ファイルを作成し、親で子を読みます。

: ChildComponent.vue

<template>
  string
</template>

子では処理不要なので、文字を書いているだけです。

: ParentComponent.vue

<template>
  <ChildComponent />
</template>

<script>
import ChildComponent from "xxxx/ChildComponent.vue";

export default {
  components: { ChildComponent },
};
</script>

親では子の vue ファイル、ChildComponent.vue を使用するために ChildComponent.vue を import します。

そのうえで、html 側で実際に使用する箇所に <ChildComponent /> と記述すれば OK です。

v-bind (単方向バインディング: 親 → 子)

Component の呼び出し方法がわかったので、次に親 → 子の Binding を説明します。

親で子のテキストを変更可能にするイメージです。

以下のコードは親で設定したテキストを子で表示します。

: ChildComponent.vue

<template>
  {{bindName}}
</template>

<script>
export default {
  props: ["bindName"],
};
</script>

子では親からのデータを受け取るため、props を用意します。

受け取るデータの名前は親と子で連携させる必要があります。今回は bindName と名付けます。

props は配列型なので、親から受け取るデータを複数持つこともできます。

: ParentComponent.vue

<template>
  <ChildComponent :bindName="dataName" />
</template>

<script>
import ChildComponent from "xxxx/ChildComponent.vue";

export default {
  components: { ChildComponent },

  data() {
    return {
      dataName: 'string'
    };
  },
};
</script>

親では html 側で呼び出します。呼び出す時に :bindName="dataName" と属性が設定されています。

ここで親と子のデータをバインド、連携させています。

  • bindName は子の props で設定した名前
  • dataName は親で扱っているデータの名前

これで、親 → 子の Binding は完了です。

v-on (単方向バインディング: 子 → 親)

次に、子 → 親の Binding を説明します。

子で発生したイベントを親に検知、引き継ぐイメージです。

以下のコードは子のテキストをクリックすると親でイベントを検知して、親で表示されているテキスト内容が string → モジ に変更します。

: ChildComponent.vue

<template>
  <div>
    <div @click="clickText()">
      クリックして変更
    </div>
  </div>
</template>

<script>
export default {

  methods: {
    clickText() {
      this.$emit('onName', 'モジ');
    }
  }
};
</script>

子ではクリックイベントを設定します。@click がクリックイベント設定です。

script 側では対象の Function 内で emit と記述しています。これが、子から親にイベントを検知させる方法です。

  • 第一引数の onName は検知させたい名前
  • 第二引数の モジ は実際に送るデータ (オブジェクト型でも OK)

これで「クリックして変更」をクリックすると親の onName に伝播します。

: ParentComponent.vue

<template>
  {{dataName}}
  <ChildComponent @onName="changeName"/>
</template>

<script>
import ChildComponent from "xxxx/ChildComponent.vue";

export default {
  components: { ChildComponent },

  data() {
    return {
      dataName: 'string'
    };
  },

  methods: {
    changeName(item) {
      this.dataName = item
    }
  }
};
</script>

親では基本的に v-bind と同様のことをしています。

他の追加処理はテキストの変更処理です。methods 内の changeName 引数に emit で設定した値が梱包されています。

これで、子 → 親の Binding は完了です。

応用編

今までは単方向バインディングのみだったので、双方向にデータを受け渡すことができません。

そこで以下からは、双方向バインディングの実装方法を解説します。

双方向バインディングが最も難しいので頑張りましょう。

v-bind と v-on (双方向バインディング)

Vue.js の双方向バインディングは大きく 2 種類の方法があります。

最初に最もベーシックな方法を解説します。

上記で解説した

  • v-bind (単方向バインディング: 親 → 子)
  • v-on (単方向バインディング: 子 → 親)

組み合わせる方法です。

以下のコードの概要です。

  1. 親で子で表示する文字列を設定 (string)
  2. 子でクリックすると親にクリックイベントを送る (モジと書かれたデータを送信)
  3. 親で文字列が string → モジ に変更
  4. 子の string がモジに変更

先程までは子、親の順に書きましたが、理解しやすさ優先でここからは親、子の順に書きます

: ParentComponent.vue

<template>
  <ChildComponent :bindName="dataName" @onName="changeName"/>
</template>

<script>
import ChildComponent from "xxxx/ChildComponent.vue";

export default {
  components: { ChildComponent },

  data() {
    return {
      dataName: 'string'
    };
  },

  methods: {
    changeName(item) {
      this.dataName = item
    }
  }
};
</script>

行っていることは v-bind と v-on をやっているだけです。親はそこそこシンプルです。

: ChildComponent.vue

<template>
  <div>
    {{bindName}}
    <div @click="clickText()">
      クリックして変更
    </div>
  </div>
</template>

<script>
export default {
  props: ["bindName"],

  methods: {
    clickText() {
      this.$emit('onName', 'モジ');
    }
  }
};
</script>

子も同様に v-bind と v-on をやっているだけです。

分かりづらい場合は、上で書いた順序通りに処理を追うと理解しやすいです

sync (双方向バインディング)

v-bind と v-on で双方向バインディングすると処理が少し複雑になります。

そこで、超応用の sync の登場です。

sync は簡単に説明すると v-bind を同期処理に変換します。

以下のコードでも先程と同じような処理を行っています。

  1. 親で子で表示する文字列を設定 (string)
  2. 子でクリックすると親にクリックイベントを送る (モジと書かれたデータを送信)
  3. 親で文字列が string → モジ に変更
  4. 子の string がモジに変更

: ParentComponent.vue

<template>
  <ChildComponent :bindName.sync="dataName" />
</template>

<script>
import ChildComponent from "xxxx/ChildComponent.vue";

export default {
  components: { ChildComponent },

  data() {
    return {
      dataName: 'string'
    };
  },
};
</script>

親の処理がスッキリしましたね。

ポイントは bindName.sync です。sync を書くことで v-on で行っていた代入処理を省略できます。

: ChildComponent.vue

<template>
  <div>
    {{bindName}}
    <div @click="clickText()">
      クリックして変更
    </div>
  </div>
</template>

<script>
export default {
  props: ["bindName"],

  methods: {
    clickText() {
      this.$emit('update:bindName', 'モジ');
    }
  }
};
</script>

子も少し変化しています。emit の第一引数に update が追加されています。

update を書くことで、親の sync に通知がいく仕組みです。

v-on と sync の違い

紹介したとおり sync だと処理を省略して書けるので便利ですが、注意点もあります。

sync は同期処理なので、フィルター処理をはさみたい時などデータを加工したい時は使用できません

双方向バインディングは以下の使い分けをおすすめします。

  • vue ファイル間でデータを加工するなら v-bind と v-on
  • vue ファイル間でデータを加工しないなら sync

まとめ

今回は Vue.js の Component と Binding を紹介しました。

とても重要な機能なので、何回も読み直してマネぶことをおすすめします。

関連記事: