LoginSignup
2
0

More than 3 years have passed since last update.

Vue.js コンポーネント

Last updated at Posted at 2020-05-08

Vue.js コンポーネント

前回の記事はこちら
Vue.js フォーム入力バインディング

コンポーネントとは

ページを構成するUI部品で再利用可能なインスタンスです。

HTMLベースのテンプレートとjavascriptで書かれたロジックで構成されます。

コンポーネント使うメリットは以下です。

①再利用ができる

②メンテナンス性が高まる

グローバル登録

Helloと出力するコンポーネントを作成し複数回利用します。
jsfiddleで実際に記述しながら読むことをおすすめします。

index/html
<div id="app">

  <hello-component></hello-component>
  <hello-component></hello-component>
  <hello-component></hello-component>

</div>
<script src ="https://cdn.jsdelivr.net/npm/vue@2.5.16/dist/vue.js"></script>
index.js
Vue.component( 'hello-component',{
  template:'<p>Hello</p>'
})

var app = new Vue({
  el:'#app',
})

実行結果
Image from Gyazo

コンポーネントの記述は第1引数にコンポーネント名を第2引数に処理内容を記述しましょう。

グローバル登録されたコンポーネントはすべてのVueインスタンスから利用可能です。

ローカル登録

特定のVueインスタンス配下でのみ利用するコンポーネントは
ローカル登録によってスコープ(範囲)を狭めることができます。

さきほどグローバル登録したコンポーネントをローカル登録に変更します。

index/html
<div id="app">

  <hello-component></hello-component>
  <hello-component></hello-component>
  <hello-component></hello-component>

</div>
<script src ="https://cdn.jsdelivr.net/npm/vue@2.5.16/dist/vue.js"></script>
index.js
var helloComponent = {
  template:"<p>Hello</p>"
}

var app = new Vue({
  el:'#app',
  components:{
    'hello-component':helloComponent
  }
})

実行結果
Image from Gyazo

まず使用するVueインスタンスよりも先にコンポーネントを定義します。
次にvueインスタンス内のコンポーネントオプションにプロパティとして設定しましょう。

コンポーネント名

コンポーネント名を登録する際はハイフンを1つ以上含む(ケバブケース)必要があります。

例)
・hello-component OK
・button-counter OK
・hello NG
・helloComponent NG キャメルケースのためNG

理由は既に存在するHTMLや将来定義されるHTML要素との衝突を避けるためです。

ただしVue.jsのスタイルガイドではパスカル記法(全ての単語の先頭が大文字)を
推奨していますので状況に応じて混在しないように使い分けることをおすすめします。
Vue.jsスタイルガイド

index/html
<!--NG記述です-->
<div id="app">

  <hello></hello> 
  <hello></hello> 
  <hello></hello> 

</div>
<script src ="https://cdn.jsdelivr.net/npm/vue@2.5.16/dist/vue.js"></script>

index.js
//NG記述です
var helloComponent = {
  template:"<p>Hello</p>"
}

var app = new Vue({
  el:'#app',
  components:{
    'hello':helloComponent
  }
})

※実行結果として動作しますが、仮に将来helloというタグがHTMLで定義された場合は衝突します。

コンポーネントのオプション

ボタンを押すとクリック数をカウントするコードをコンポーネントで記述しましょう。

index/html
<div id="app">

  <button-counter></button-counter>
  <button-counter></button-counter>
  <button-counter></button-counter>

</div>
<script src ="https://cdn.jsdelivr.net/npm/vue@2.5.16/dist/vue.js"></script>
index.js
Vue.component('button-counter',{
  data:function(){
    return {
      count:0
    }
  },
  template:'<button v-on:click="count++">{{ count }}</button>'
})

var app = new Vue({
  el:'#app'
})

実行結果
Image from Gyazo

それぞれのボタンはカウント数を独自に保持しています。
これはコンポーネントを作成するたびに新しいインスタンスが作成されるためです。

コンポーネントのdataは直接定義されず関数となる必要があります。

index.js
//例 直接定義
data:{
  count:0
}

//例 関数定義
data:function(){
  return{
    count:0
  }
}

理由は各インスタンスが独自にオブジェクトを利用できるようにするためです。

またテンプレートのルート要素は単一である必要があります。
上記のカウンターに"count:"のラベルをつけてみましょう。

index/html
<div id="app">

  <button-counter></button-counter>
  <button-counter></button-counter>
  <button-counter></button-counter>

</div>
<script src ="https://cdn.jsdelivr.net/npm/vue@2.5.16/dist/vue.js"></script>
index.js
Vue.component('button-counter',{
  data:function(){
    return {
      count:0
    }
  },
  template:'<span>count:</span><button v-on:click="count++">{{ count }}</button>'
})

var app = new Vue({
  el:'#app'
})

実行結果
Image from Gyazo
Image from Gyazo

上記の記述ではspanとbuttonで要素が複数になっているためコンパイルエラーが発生します。
この場合はdivタグなどで囲んで要素を1つにまとめる必要があります。

index.js
//テンプレートを修正
Vue.component('button-counter',{
  data:function(){
    return {
      count:0
    }
  },
  template:'<div><span>count : </span><button v-on:click="count++">{{ count }}</button></div>' //divで囲んで単数化
})

var app = new Vue({
  el:'#app'
})

実行結果
Image from Gyazo

コンポーネント間の通信

複数のコンポーネントを並列または入れ子に配置された場合
スコープ(データの有効範囲)という概念が発生します。

コンポーネントで定義された情報(データ、メソッドなど)に
アクセスできるのはそのコンポーネントだけということになります。

次回はトランジションです。
Vue.js トランジション

2
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
0