Vue2 コンポーネントまとめ ①

##はじめに
Vue.jsを勉強していてコンポーネントって大事そうなんだけど、いまいちよくわかっていないので
手を動かしながら学んだことの備忘録
Vue3もリリースされていますが、<strong>今回はVue2についてです。</strong>


- [Vue2 コンポーネントまとめ②](https://qiita.com/morioka1206/items/b74978246da99407cd38)

<br>
##Vue.jsコンポーネントとは
```vue
// button-counter と呼ばれる新しいコンポーネントを定義します
Vue.component('button-counter', {
  data: function () {
    return {
      count: 0
    }
  },
  template: '<button v-on:click="count++">You clicked me {{ count }} times.</button>'
})
```
>コンポーネントは名前付きの再利用可能な Vue インスタンスです。この例の場合、<button-counter>です。このコンポーネントを new Vue で作成されたルート Vue インスタンス内でカスタム要素として使用することができます。
>(Vue.js公式より引用）

ふむふむ。再利用できるインスタンスかあ。Railsでいうと、ヘッダーとかフッター、サイドバー、フォームなどを_form.html.erbなどでrenderメソッドで呼び出したりしますがそんな感じってことですね。

これにより開発、メンテナンスの効率が格段に上がるとのことです。

<br>
##コンポーネントの設計
####コンポーネントの作り方
```vuejs:javascript
Vue.component('コンポーネントの名前',{
  template  :  'HTMLに表示させたい内容'
})
```

ちなみにVue3はこんな書き方になるようです。

```
Vue.createApp({
    
    // 省略

})
.component('コンポーネントの名前', {
    template: 'HTMLに表示させたい内容'
})
.mount('#app');
```
今回は特に説明はしません。Vue3でやるとエラーになることだけご理解ください。
また<strong>コンポーネントの名前はケバブケース（hello-world）またはパスカルケース（HelloWorld)とする必要があります。</strong>

####コンポーネントの例
```
Vue.component('hello-world', {
  template : '<h1>Hello World</h1>'
})
```
これでhello-worldというコンポーネントができました。
これをVueインスタンス下にあるhtmlから直接コンポーネントを利用することができます。
コンポーネント作成時に登録した名前のタグを組み込みます。
<strong>今回はとid='app'として進めていきます。</strong>

<p class="codepen" data-height="265" data-theme-id="light" data-default-tab="result" data-user="rm5912" data-slug-hash="PoWLvqj" style="height: 265px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;" data-pen-title="Vue.js vueコンポーネント練習1">
  <span>See the Pen <a href="https://codepen.io/rm5912/pen/PoWLvqj">
  Vue.js vueコンポーネント練習1</a> by morioka (<a href="https://codepen.io/rm5912">@rm5912</a>)
  on <a href="https://codepen.io">CodePen</a>.</span>
</p>
<script async src="https://cpwebassets.codepen.io/assets/embed/ei.js"></script>

```html:html
<div id="app">
  <hello-world></hello-world>
</div>
```



```vuejs:javascript
Vue.component('hello-world',{
  template : '<h1>Hello World</h1>'
})

new Vue({
  el: '#app'
})
```
コンポーネントの定義はnew Vueよりも前に記述する必要があります。
new Vueのあとに定義した場合はエラーになり、
ページに何も表示されなくなります。

<br>
##コンポーネントの再利用
コンポーネントの特性と言っていい、再利用。
hello-worldのタグを複数記述するだけで同じ内容を表示させることができます。

<p class="codepen" data-height="300" data-theme-id="light" data-default-tab="result" data-user="rm5912" data-slug-hash="ZELPNaN" style="height: 265px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;" data-pen-title="Vue.js vueコンポーネント練習2">
  <span>See the Pen <a href="https://codepen.io/rm5912/pen/ZELPNaN">
  Vue.js vueコンポーネント練習2</a> by morioka (<a href="https://codepen.io/rm5912">@rm5912</a>)
  on <a href="https://codepen.io">CodePen</a>.</span>
</p>
<script async src="https://cpwebassets.codepen.io/assets/embed/ei.js"></script>

<br>
##グローバルコンポーネントとローカルコンポーネント
コンポーネントは２種類あります。
<strong>グローバルコンポーネントとローカルコンポーネントです。</strong>
今まで説明してきたのはグローバルコンポーネントでVue.componentを使う場合はグローバルへの登録になり、別のコンポーネントで利用することができます。

ある特定のコンポーネントだけで利用したい場合はローカルで登録し、利用することができます。
ローカルへの登録はVueインスタンスにcomponentsプロパティを追加することで行います。

```vuejs:javascript
var app = new Vue({
  el: '#app',
  data: {
  },
  components: {
    'hello-world': {
      template: '<h1>Hello World</h1>'
    }
  }
})	
```
<br>
##グローバルとローカルの違い

<p class="codepen" data-height="530" data-theme-id="light" data-default-tab="html,result" data-user="rm5912" data-slug-hash="vYgPqYd" style="height: 265px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;" data-pen-title="Vue.js vueコンポーネント練習3">
  <span>See the Pen <a href="https://codepen.io/rm5912/pen/vYgPqYd">
  Vue.js vueコンポーネント練習3</a> by morioka (<a href="https://codepen.io/rm5912">@rm5912</a>)
  on <a href="https://codepen.io">CodePen</a>.</span>
</p>
<script async src="https://cpwebassets.codepen.io/assets/embed/ei.js"></script>

```vuejs:javascript
Vue.component('hello-world',{
  template : '<h1>Hello World</h1>'
})

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

var app2 = new Vue({
  el: '#app2',
  components: {
    'hello-vue': {
      template: '<h1>Hello Vue.js</h1>'
    }
  }
})
```

```html:html
<div id="app1">
  <h2>App1</h2>
  <hello-world></hello-world>
  <hello_vue></hello_vue>
</div>

<div id="app2">
  <h2>App2</h2>
  <hello-world></hello-world>
  <hello-vue></hello-vue>
</div>
```
１つ目のapp1のVueインスタンスではapp2にローカル登録したhello-vueが利用できないため
Hello Vue.jsが表示されていませんが、ローカル登録されたapp2には表示されています。

<br>
##templateに複数のタグ
Vue3では制限がなくなっているようですが、Vue2の場合複数のタグをtemplateに入れる場合には
注意が必要です。
どうやらコンポーネントテンプレートは1つのルート要素を持たなければならないという規則があるようです。

```vuejs:javascript
Vue.component('hello-world',{
  template: '<p>{{ message }}</p><p>Hello World</p>',
  data: function(){
    return {
      message : 'Hello Vue'
    }
  }
})
```	
この場合2つ目のHello Worldが表示されていません。

<p class="codepen" data-height="265" data-theme-id="light" data-default-tab="js,result" data-user="rm5912" data-slug-hash="vYgPqrQ" style="height: 265px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;" data-pen-title="Vue.js vueコンポーネント練習4">
  <span>See the Pen <a href="https://codepen.io/rm5912/pen/vYgPqrQ">
  Vue.js vueコンポーネント練習4</a> by morioka (<a href="https://codepen.io/rm5912">@rm5912</a>)
  on <a href="https://codepen.io">CodePen</a>.</span>
</p>
<script async src="https://cpwebassets.codepen.io/assets/embed/ei.js"></script>

pタグが2つ挿入されているため、1つのルート要素になっていなく2つのルート要素になっているからです。
そのため、この2つのpタグを含む上位のタグをつける必要があります。（divなど）
上位タグをつけることで1つのルート要素になり、2つのpタグはdivの子要素となりHello Worldも表示されるようになります。

```vuejs:javascript
Vue.component('hello-world',{
  template: '<div><p>{{ message }}</p><p>Hello World</p></div>',
  data: function(){
    return {
      message : 'Hello Vue'
    }
  }
})	
```

<p class="codepen" data-height="265" data-theme-id="light" data-default-tab="js,result" data-user="rm5912" data-slug-hash="LYxaKaB" style="height: 265px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;" data-pen-title="Vue.js vueコンポーネント練習5">
  <span>See the Pen <a href="https://codepen.io/rm5912/pen/LYxaKaB">
  Vue.js vueコンポーネント練習5</a> by morioka (<a href="https://codepen.io/rm5912">@rm5912</a>)
  on <a href="https://codepen.io">CodePen</a>.</span>
</p>
<script async src="https://cpwebassets.codepen.io/assets/embed/ei.js"></script>

<br>
##コンポーネントでdataを使う
コンポーネントでもdataプロパティは使えるのですが
<strong>dataは関数にする必要があります。</strong>

```vuejs:javascript
Vue.component('hello-world',{
  template: '<h1>{{ message }}</h1>',
  data: function(){
    return {
      message : 'Hello Vue'
    }
  }
})
```
####複数のdataを取り扱う場合

```vuejs:javascript
data: function(){
    return {
      message : 'Hello Vue',
      message2 : 'Hello World'
    }
  }
```
<strong>dataを関数にすることでdataを持つ複数のコンポーネントを使った場合に
コンポーネントごとにdataの独立の値を保持することができます。</strong>

<br>
##コンポーネントでmethodsを使う
コンポーネントはdataプロパティだけでなくmethodsプロパティも使うことができます。
ボタンを押すとアラートが表示されます。

```vuejs:javascript
Vue.component('hello-world',{
  template:
    '<button v-on:click="alert">アラート</button>'
  ,
  methods: {
    alert: function(event) {
      alert("アラートが表示されました")
    }
  }
})	

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

<p class="codepen" data-height="265" data-theme-id="light" data-default-tab="result" data-user="rm5912" data-slug-hash="MWJxNor" style="height: 265px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;" data-pen-title="Vue.js vueコンポーネント練習6">
  <span>See the Pen <a href="https://codepen.io/rm5912/pen/MWJxNor">
  Vue.js vueコンポーネント練習6</a> by morioka (<a href="https://codepen.io/rm5912">@rm5912</a>)
  on <a href="https://codepen.io">CodePen</a>.</span>
</p>
<script async src="https://cpwebassets.codepen.io/assets/embed/ei.js"></script>

<br>
##コンポーネントを複数作成した場合の独立性
コンポーネントは再利用できることを学びました。
コンポーネントを複数作成した場合はそれぞれが独立したものとして作成されます。

<p class="codepen" data-height="265" data-theme-id="light" data-default-tab="result" data-user="rm5912" data-slug-hash="yLgwmqK" style="height: 265px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;" data-pen-title="Vue.js vueコンポーネント練習7">
  <span>See the Pen <a href="https://codepen.io/rm5912/pen/yLgwmqK">
  Vue.js vueコンポーネント練習7</a> by morioka (<a href="https://codepen.io/rm5912">@rm5912</a>)
  on <a href="https://codepen.io">CodePen</a>.</span>
</p>
<script async src="https://cpwebassets.codepen.io/assets/embed/ei.js"></script>

Upボタンでカウントが増えてDownボタンでカウントが減りますが、３つのコンポーネントは独立した状態で動作しているのがわかります。
<br>
##template内のhtmlを改行する
templateに記述するhtmlは当然長くなることが多くなります。その場合シングルクオーテーションではエラーになり表示されません。

```vuejs:javascript
Vue.component('hello-world',{
    template: '<p>ロレム・イプサムの嘆き、トマト大好き学部のエリット、しかし時と活力、そのような労働と悲しみ、ブラインド行うにはいくつかの重要な事柄に座ります。
              長年にわたり、私は学区と長寿であれば、そのような刺激の取り組み、彼女のうち、運動の利点を分注を邪魔されたする人が来ます。
              クピダタットのつるの痛みになりたい宿題に、批判されてきたら痛み、マグナ逃亡しても結果の喜びを生成しません。先例クピダタットブラックは先例していない、つまり、彼らはあなたの悩みに責任がある人の、一般的な義務を捨て、魂を癒しています。</p>'
})	

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

<p class="codepen" data-height="265" data-theme-id="light" data-default-tab="result" data-user="rm5912" data-slug-hash="dyNrxLP" style="height: 265px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;" data-pen-title="Vue.js vueコンポーネント練習8">
  <span>See the Pen <a href="https://codepen.io/rm5912/pen/dyNrxLP">
  Vue.js vueコンポーネント練習8</a> by morioka (<a href="https://codepen.io/rm5912">@rm5912</a>)
  on <a href="https://codepen.io">CodePen</a>.</span>
</p>
<script async src="https://cpwebassets.codepen.io/assets/embed/ei.js"></script>

何も表示されていません。

templateで設定するhtmlが長い場合はバッククォートを使います。（``)
バッククォートで囲むと改行を行っても表示されています。

<p class="codepen" data-height="265" data-theme-id="light" data-default-tab="result" data-user="rm5912" data-slug-hash="ZELPggq" style="height: 265px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;" data-pen-title="Vue.js vueコンポーネント練習9">
  <span>See the Pen <a href="https://codepen.io/rm5912/pen/ZELPggq">
  Vue.js vueコンポーネント練習9</a> by morioka (<a href="https://codepen.io/rm5912">@rm5912</a>)
  on <a href="https://codepen.io">CodePen</a>.</span>
</p>
<script async src="https://cpwebassets.codepen.io/assets/embed/ei.js"></script>

```vuejs:javascript
Vue.component('hello-world',{
    template: `<p>ロレム・イプサムの嘆き、トマト大好き学部のエリット、しかし時と活力、そのような労働と悲しみ、ブラインド行うにはいくつかの重要な事柄に座ります。
              長年にわたり、私は学区と長寿であれば、そのような刺激の取り組み、彼女のうち、運動の利点を分注を邪魔されたする人が来ます。
              クピダタットのつるの痛みになりたい宿題に、批判されてきたら痛み、マグナ逃亡しても結果の喜びを生成しません。先例クピダタットブラックは先例していない、つまり、彼らはあなたの悩みに責任がある人の、一般的な義務を捨て、魂を癒しています。</p>`
})	

var app = new Vue({
  el: '#app'
})
```
<br>

##終わりに
コンポーネントについてまとめてみました。
まだまだありますがとりあえずはここら辺で①を終わりにします。
気づいたことありましたら教えていただけるとありがたいです。
②に続きます。


>参考サイト
[Vue.js公式サイト](https://jp.vuejs.org/v2/guide/components.html)
[REFFECT vue.jsコンポーネントの基礎](https://reffect.co.jp/vue/vue-component-basic#data)
[Qiita Vue】単一ファイルコンポーネントの命名規則まとめ【ファイル名から記法まで】](https://qiita.com/ngron/items/ab2a17ae483c95a2f15e)