見出し画像

Vue.js基礎~コンポーネント~

こんにちは。PoSoです。
今回もまただいぶ日があいてしまいました…
習慣を作るというのはなかなかどうして難しいもので、様々な状況と心理の変化でどうしても続かないです。
習慣について色々なビジネス系YouTuberの動画をみたり、本を読んでみたりと試行錯誤してはいますが。
学習自体は継続できているのであとは徐々に時間を増やしていく努力をしていきたいと思っております。

さて今回はVue.jsのコンポーネントの概念と使用法についてまとめました。
今までそういうもんだとして使っていたコンポーネントでしたが、新しく知れたことが沢山ありました。
これを読んでくれた方にもそういった新しい発見があれば幸いです。

コンポーネントとは

コンポーネントは再利用可能な Vue インスタンスを作ることに使います。

<div id="app"></div>
<div id="app"></div>
<div id="app"></div>
new Vue({
	el:'#app',
	data:{
		number: 12
	},
	template: '<p>いいね({{ number }})</p>'
})

まずは良くない例ですが、コンポーネントを使わずとも div タグを何個も作ればその数の分描画されるとはおもいませんか?
しかし結果は1度しか描画されません。
たとえ el プロパティをクラスにしようが要素にしようが同じです。
これは Vue.js の仕様上、初めに適用された要素があったら、それ以降を無視するという特性があるためです。

ここで使用されるのがコンポーネントというわけです。

/* Vue.component('コンポーネント名', {オプション}) */


Vue.component('my-component', {
    data:{
		number: 12
	},
	template: '<p>いいね({{ number }})</p>'
})


nwe Vue({
    el: '#app'
})

コンポーネントを宣言すれば、以降 Vue インスタンス内で使用が可能になります。

<div id="app">
	<my-component></my-component>
</div>

これでコンポーネントを描画させることができました。

しかしここで問題が1つあります。
data の値が出力されていません。
これがコンポーネントの大きな特徴なのですが、コンポーネントにおいてdata は関数でなくてはいけません。

data: function(){
	return {
        number: 12
    }
}

これでコンポーネント完成です。
あとは何度でも利用可能です。

<div id="app">
	<my-component></my-component>
    <my-component></my-component>
    <my-component></my-component>
</div>

次はなぜdataが関数である必要があるのかについて解説します。

dataがコンポーネントにおいて関数である理由

結論から言うと、dataがオブジェクトであった場合、参照により共有されてしまうからです。
同じdataを共有してしまうということです。
実際に見てみます。

+1を押すと、3つすべての数字が増えているのがわかると思います。
でも考えてみればこれは合理的で、インスタンス内の template も methods も中身は一緒です。
同じものを共有して使いまわす方が効率がいいに決まっています。
ただ data だけは同じであってはいけないので解決策として関数で指定してね、となっているわけです。

ローカル登録とグローバル登録

これまでコンポーネントの登録を new Vue() の外側で Vue.component() と宣言してやってきました。
これがグローバル登録といわれる登録方法です。
どのVueインスタンスでもコンポーネントが使用可能になります。

別の登録方法としてローカル登録があります。
こちらは特定のVueインスタンスでのみ使えるコンポーネントを作ります。​

var component = {
    ...
}

このように変数を作ってコンポーネントの中身を入れます。

new Vue({
	el: "#app",
	components: {
		"my-component": component
	}
})

そしてVueインスタンスでコンポーネントの登録をします。
この時新しいオプションの「components」を使います。
“コンポーネント名”:変数名のように定義します。

見て分かる通り、app ではコンポーネントが表示されているのに対して、app2 ではコンポーネントが表示されていません。

実際はローカル登録の方を主に使用します。
理由としては、グローバル登録したコンポーネントが実はあまり使われないコンポーネントで、そのままファイルに残ってしまって、最終的なファイルのサイズが増加してしまう、などの弊害があるからです。

「import App from './App.vue'」を理解する

ここからは以前Vue CLI で作成したファイルを見ていきます。
main.js で少しわからなかった箇所があったのでそこを解説します。

import App from './App.vue'

これはコンポーネントのオブジェクトをインポートしています。
コンポーネントのローカル登録でやったと思うのですが、オブジェクトにしていました。

var component = {
    data:{...},
    template: ...,
    methods: {...}
}

中に data や methods など色々入っているものがコンポーネントの中身です。

しかし .vue ファイルは単一ファイルコンポーネントといわれ、3つのファイルに分かれていましたよね。
それをインポートするとAppにオブジェクトとして格納されます。
それを可能にしているのがVue CLI です。
Vue CLI が .vue ファイルを理解して import 時にオブジェクトに変換して返してくれています。

実際に目で見た方が早いと思うので見てみましょう。
console.log(App) で表示させます。

画像1

このようにオブジェクトでコンポーネントが表示されています。

単一ファイルコンポーネントの使い方

実際にVue CLI で作ったプロジェクトを編集していきます。
App.vue を編集します。

<template>
 <p>いいね({{ number }})</p>
</template>

<script>
export default {
 data() {
   return {
     number: 5
   }
 }
}
</script>

ほぼ今までと同じですが、script 部分はexport default から始まり、コンポーネントオプション( methods、data など )を置いていくことになります。​

補足をすると script は ES6 の文法で書いていきます。
babel がデフォルトでインストールされているからです。
ES5 ではこのようになります。

export default {
 data: function() {
   return {
     number: 5
   }
 }
}

単一ファイルコンポーネントのグローバル登録

コンポーネントを作成してApp.vue で表示させてみます。

今回は LikeNumber.vue を src\components に作成し、上で書いたコードをそのまま持ってきます。
それをApp.vue で登録していきます。

グローバル登録はmain.jsで行います。

import Vue from 'vue'
import App from './App.vue'
import LikeNumber from './components/LikeNumber.vue' //このコードを追加

Vue.config.productionTip = false
Vue.component('LikeNumber', LikeNumber) //このコードを追加

new Vue({
 render: h => h(App),
}).$mount('#app')

これで登録完了です。

あとは App.vue で表示しましょう。

<template>
  <LikeNumber></LikeNumber>
</template>

ここで1つ注意点があります。

template はルート要素を1つにしなければいけないというルールがあります。
どういうことか説明します。

<template>
 <p>いいね({{ number }})</p>
 <button @click="increment">+1</button>
</template>

<script>
export default {
 data() {
   return {
     number: 5
   }
 },
 methods: {
   increment() {
     this.number += 1
   }
 }
}
</script>

template に注目してください。
現在 p と button という2つの要素があります。
これは実際にエラーになります。

画像2

黄色いマーカーを引いた部分に、ルート要素は1つにしなさいと書かれています。

ではどうするか。
答えは簡単でdivタグで囲ってあげればいいだけです。

<template>
<div>
 <p>いいね({{ number }})</p>
 <button @click="increment">+1</button>
</div>
</template>

このように単一ファイルコンポーネントを使用する場合は、必ずtemplateは1つの要素で囲ってあげることに注意しましょう。

単一ファイルコンポーネントのローカル登録

今度は LikeHeader.vue を src\components に作成します。

<template>
 <h1>いいね</h1>
</template>

これを App.vue でローカル登録し、表示させます。

<template>
 <div>
   <LikeHeader></LikeHeader> <!-- ここを追加 -->
   <LikeNumber></LikeNumber>
 </div>
</template>

//以下を追加

<script>
import LikeHeader from './components/LikeHeader.vue';

export default {
 components: {
   LikeHeader
 }
}
</script>

上でも説明したようにインポートしてコンポーネントを定義し、テンプレートで使用します。

コンポーネントの命名規則

コンポーネントの名前にはケバブケースとパスカルケースを用いることができます。

ケバブケース・・・like-header
ケバブケースは単語をハイフンで区切って指定します。
これは実際のケバブの串をハイフンに見立てたことが由来です。

パスカルケース・・・LikeHeader
パスカルケースは単語の初めを大文字にして指定するものです。

これは複数の単語を指定する時に区切りが分かりやすいようにするためのものです。

まずパスカルケースで書いた場合、template にはパスカルケースでもケバブケースでも書くことができます。

<template>
 <div>
   <LikeHeader></LikeHeader>
   <like-header></like-header>  <!-- どっちでもOK! -->
 </div>
</template>

<script>
import LikeHeader from './components/LikeHeader.vue';

export default {
 components: {
   LikeHeader
 }
}
</script>

逆に、ケバブケースで命名した場合、templateでもパスカルケースで指定する必要があります。

<template>
 <div>
   <like-header></like-header>  <!-- これ以外だめ! -->
 </div>
</template>

<script>
import LikeHeader from './components/LikeHeader.vue';

export default {
 components: {
   'like-header': LikeHeader
 }
}
</script>

ここでどっちがいいのか問題が出てくると思うのですが、基本的にはパスカルケースがよいとされています。
実際本当はどちらでもよいのですが、統一だけはしっかりするべきです。

パスカルケースがよいとされる理由もしっかり存在し、3つあります。
・JavaScript でよく使われる記法である
・HTML 要素と見分けがつきやすい
・Vue 以外のカスタム要素と見分けがつきやすい

パスカルケースで指定した場合両方の規則が使えることにも理由があります。
それは DOM テンプレートを使用する場合ケバブケースで書かなければいけないからです。
DOM テンプレートとは簡単に言うと index の div タグの中などです。

<!DOCTYPE html>
<html lang="en">
 <head>
   <meta charset="utf-8">
   <meta http-equiv="X-UA-Compatible" content="IE=edge">
   <meta name="viewport" content="width=device-width,initial-scale=1.0">
   <link rel="icon" href="<%= BASE_URL %>favicon.ico">
   <title><%= htmlWebpackPlugin.options.title %></title>
 </head>
 <body>
   <noscript>
     <strong>We're sorry but <%= htmlWebpackPlugin.options.title %> doesn't work properly without JavaScript enabled. Please enable it to continue.</strong>
   </noscript>
   <div id="app"><!-- ここです --></div>
   <!-- built files will be auto injected -->
 </body>
</html>

ブラウザは実は大文字と小文字を見分けることができません。
つまり LikeNumber は likenumber とブラウザでは処理してしまうのです。

しかしVue CLI で作成したのだから読み取って変換してくれるのでは?と考える方もいると思います。
まず index は build やコンパイルされないファイルです。
書かれたそのままがブラウザに反映されます。
さらにブラウザはまず最初にHTML要素を読み込み、その後JavaScriptを読み込む性質があります。
だから、DOM テンプレートを使用する場合はケバブケースを使用するというルールが存在するのです。

最後に余談ですがキャメルケースについても触れておきます。

キャメルケース・・・likeNumber

よくJavaScriptの変数名などに使用され、このように最初は小文字、その後大文字となるものです。
これで書いてもパスカルケースで指定した時と同様の動作をします。
しかし、Vueの公式ガイドではキャメルケースの使用は選択肢にありません。
郷に入っては郷に従えということで、キャメルケースは使用せず、パスカルケースを使用するようにしましょう。

まとめると、
・Vue CLI 上で開発するならばパスカルケース、ケバブケースどちらかに統一して使用する(お勧めはパスカルケース)
・DOMテンプレートを使用する場合はケバブケースを使用する
・原則キャメルケースは使用しない
となります。


この記事が気に入ったらサポートをしてみませんか?