【Vue.js】Vue CLIで作成したプロジェクトに新規コンポーネント(テンプレート)を追加する方法を実例で解説|拡張子.vueの単一ファイルコンポーネントの作成と読み込み方

vue-js-prograshi(プロぐらし)-kv Vue.js
記事内に広告が含まれていることがあります。

Vue CLIで作成したプロジェクトに、拡張子.vueの単一ファイルコンポーネントを追加して、それをコンポーネントとして呼び出す方法についてまとめています。


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

Vue.jsを使っていると、単一ファイルコンポーネントという言葉を頻繁に耳にします。

単一ファイルコンポーネントとは.vueというファイルの名称です。

単一ファイルコンポーネントでは、HTML, Vue.js(JavaScript), CSS(SASSなど)を一つのファイルにまとめて記述することができます

通常はばらばらと個別に作成しなければいけないファイルを1つのファイル(単一のファイル)にまとめることができます。

作成した.vueファイルは一塊の要素(コンポーネント)として、好きな場所で呼び出すことができます

このため、単一ファイルコンポーネントと呼びます。


コンポーネントの作成と読み込み手順

コンポーネントの作成と読み込みは、以下の4つのステップになります。

コンポーネントの作成と読み込み手順
  1. componentsフォルダ配下に新規ファイルを作成する。
  2. 呼び出したいコンポーネントの中にファイルをインポート(import)する。
  3. 呼び出したいコンポーネントの中でcomponentとして定義する。
  4. templateの中でコンポーネントを呼び出す。


なお、1つのコンポーネントの中で複数のコンポーネントを呼び出したい場合も、同じ手順の繰り返しになります。(例:ヘッダーやフッターをコンポーネントとして作成し、読み込む場合)


componentsフォルダ配下に新規ファイルを作成する

ファイルの作成場所

まず、単一ファイルコンポーネント.vueファイルをsrcディレクトリの中の、componentsディレクトリ配下に作成します。

デフォルト状態では、componentsは以下のようになっています。

このディレクトリにファイルを追加します。

point

単一ファイルコンポーネントのファイルを保存する場所は「src」の中の「components」ディレクトリ配下が一般的ですが、必ずしもここである必要はありません。

srcの下に専用のフォルダを作成してもいいですし、componentsの中に専用のフォルダを作成してその中に設置することもできます。

その際は、次項のファイルインポート時に指定するパスを適宜変更する必要があります。


ファイルの命名規則

ファイル名はコンポーネントの命名規則「大文字始まり、キャメルケース(単語の冒頭を大文字でつなぐ)」のが一般的です。

例: User.vue や UserDetail.vueなど


ファイルの中身

ファイルの中には templateタグ、scriptタグ、styleタグで囲まれた場所を作成します。

以下が.vueファイルのデフォルトのテンプレートになります。

<template>
  
</template>

<script>
export default {

}
</script>

<style>

</style>

templateタグの中に、ブラウザに表示するHTMLのソースコードを記載します。

scriptタグの中がJavaScriptの記述、export defaultの中がVue.jsの記述になります。

styleタグの中がCSSスタイルを記述する場所です。指定方法によってはSASS(SCSS)も使用できます。


実例

例えば「UserDetail.vue」という単一ファイルコンポーネントを作成する場合は以下のようになります。

ここでは読み込みの手順を確認するために超シンプルなコードにします。(VueのコードやCSSを記述したものは別途解説します)

<template>
    <div>
      <h1 style="color: red">User Detailの単一ファイルコンポーネントです</h1>
    </div>
</template>

<script>
export default {

}
</script>

<style>

</style>

.vueのデフォルトのテンプレートのtemplateタグの中に、divとh1を追加しただけです。


呼び出したいコンポーネントの中にファイルをインポート(import)する

続いて作成した.vueファイルを読み込みます。

作成したコンポーネントを呼び出したいファイルの中に、作成したファイルを変数名を指定してインポートします。

記述する領域はJavaScriptの領域です。(※scriptタグの中、export defaultの外

import 変数名 from 'ファイルパス'
.vueファイルインポート時のポイント
  1. 変数の名前はファイル名と一致させるのが一般的です。
  2. ファイルパスは、現在のファイルから見た相対パスを記述します。
  3. .vueという拡張子は省略できます。



実例

Vue CLIのプロジェクトを生成したときに画面上に読み込まれている、HelloWorld.vueの中で、新たに作成したコンポーネントを読み込んでみます。

HelloWorld.vueを開いて、scriptタグの直下に以下を追記します。

import UserDetail from './UserDetail'

パスの部分は.vueを省略しています。「./UserDetail.vue」と同じです。「./」は現在のファイルと同じ階層であることを示す相対パスです。

全体的なコードは以下のようになります。

<template>
  省略(デフォルトのまま)
</template>

<script>
import UserDetail from './UserDetail'

export default {
  name: 'HelloWorld',
  props: {
    msg: String
  }
}
</script>

<!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped>
  省略(デフォルトのまま)
</style>


呼び出したいコンポーネントの中でcomponentとして定義する

.vueファイルをインポートしただけではコンポーネントとして使えません。

次に、Vueの領域の中で、読み込んだファイルをコンポーネントとして登録します。

export defaultの中に、componentsオブジェクトを作成し、その中にテンプレート名を記述します。

<script>
import 変数名 from 'ファイルパス'

export default {
  components: {
    変数名
  }
}
</script>
point

componentsの中で指定しているのは変数名だけです。これはプロパティ名と値となる変数名が同じ場合に可能な省略した書き方になります。

  components: {
    HelloVue
  }

例えば上記は以下と同じです。

  components: {
    HelloVue : HelloVue
  }

左側のコンポーネント名となるプロパティ名を変えることもできます。

  components: {
    Child : HelloVue
  }

この場合、外部の.vueファイルを「HelloVue」というモジュール名で読み込み、そのコンポーネント名を「Child」として登録したことになります。


実例

HelloWorld.vueのVue.jsの領域であるexport defaultでコンポーネント「UserDetail」を定義します。

<template>
  省略(デフォルトのまま)
</template>

<script>
import UserDetail from './UserDetail'

export default {
  name: 'HelloWorld',
  props: {
    msg: String
  },
  components: {
    UserDetail
  }
}
</script>

<!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped>
  省略(デフォルトのまま)
</style>
注意点

この時点ではコンパイル時に「error The “UserDetail” component has been registered but not used」というエラーが発生します。

これを解消するためには、次項のようにテンプレートの中で定義したコンポーネントを使用する必要があります。


templateの中でコンポーネントを呼び出す

コンポーネントの呼び出し方

最後の仕上げとして、登録したコンポーネントをtemplateの中で呼び出します。

呼び出す際は、定義したコンポーネント名をタグとして記述します。

<コンポーネント名 />
point

<コンポーネント名></コンポーネント名>のように開始タグと終了タグを記載することもできますが、間にタグや文字列を入れても無視されるため、終了タグを省略して記述するのが一般的です。


id, class, v-bind, v-model, v-on などを使う場合

呼び出すテンプレートに対して、id名や、クラス名、v-bindやv-model、クリックイベント(v-onや@)などを記載する場合は、コンポーネント名の後ろに属性として記述します。

<コンポーネント名
 id="unique-id"
 class="class-name"
 :class="プロパティ名"
 .... />
合わせて読みたい

Vue.jsで欠かせない超便利機能、v-bind, v-model, v-onなどの使い方については下記をご参考ください。


id名やclass名、:classの実例は後述しています。


実例

HelloWorld.vueのtemplateタグの上層部で定義したコンポーネント「UserDetail」を呼び出します。

<template>
  <div class="hello">
    <UserDetail />
    省略(デフォルトのまま)
  </div>
</template>

<script>
import UserDetail from './UserDetail'

export default {
  name: 'HelloWorld',
  props: {
    msg: String
  },
  components: {
    UserDetail
  }
}
</script>

<!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped>
  省略(デフォルトのまま)
</style>

以上でテンプレートの設定は完了です。


ブラウザでの呼び出し

components定義前のデフォルトの状態は以下のようになっています。(Vue CLIでプロジェクトを作成した状態)

 ↓ コンポーネント「UserDetail」を定義し呼び出した後

指定した場所に定義したコンポーネント「UserDetail」の内容が読み込まれているのがわかります。


単一ファイルコンポーネントの中でdataやCSSスタイルを設定する方法

単一ファイルコンポーネントを追加する方法がわかったところで、次に、.vueファイルを編集してdataやwatch, cssスタイルなどを追加します。


dataなどVue.jsの機能を使う方法

dataやmethodsなどVue.jsの機能を使うには、export defaultの中に記述します。export defaultの中はVue.jsの世界と考えてください。

例えば、上記のUserDetail.vueの中身を編集して、苗字と名前を入力すると、watchオブジェクトにより変更を検知して、フルネームを自動で返す処理は以下のようになります。

<template>
  <div id="user-detail">
    <h1>ユーザーの詳細ページです</h1>
    <ul class="profile-list">
      <li>苗字:<input type="text" v-model="lastName" ></li>
      <li>名前:<input type="text" v-model="firstName" ></li>
      <li>フルネーム:{{ fullName }}</li>
    </ul>
  </div>
</template>

<script>
export default {
  data(){
    return{
      lastName: '',
      firstName: '',
      fullName: '',
    }
  },
  watch:{
    lastName: function(){
      this.fullName = this.lastName + " " + this.firstName
    },
    firstName: function(){
      this.fullName = this.firstName + " " + this.lastName
    }
  }
}
</script>

<style>
</style>
合わせて読みたい

ここでは記述の仕方の説明のみになります。詳細については下記をご参考ください。


CSSスタイルを設定する

続いてCSSスタイルを設定します。スタイルはstyleタグの中に記述します。書き方はCSSファイルに記述するのと同じです。

スコープを設定する方法

styleタグの中に記述した場合だと、作成したスタイルがプロジェクト内の全てのテンプレートに反映されてしまいます。

これを、現在記述している.vueファイルのtemplateにのみ適用したい場合は、styleタグの後ろに scoped属性を記述します。

<style scoped>
</style>


SASSやSCSSを使う方法

SASSやSCSSの記述でスタイルを書くこともできます。

vue create時にsassを使う設定にしていない場合は別途、sass-loaderとsassの2つのパッケージを別途インストールする必要があります。

lang属性を記述してその値を「scss」や「sass」とします。scoped属性と併用することもできます。

<style lang="scss" scoped>
</style>
合わせて読みたい

sass-loaderとsassの2つのパッケージをインストールする方法については下記をご参考ください。

Vue CLIでsassやscssを使う方法(style lang=”scss” scoped)エラー対処法


実例

コンポーネント「UserDetail」のtemplateタグ内のid="user-detail"class="profile-list"に対してスタイルを設定します。

<template>
  <div id="user-detail">
    <h1>ユーザーの詳細ページです</h1>
    <ul class="profile-list">
      <li>苗字:<input type="text" v-model="lastName" ></li>
      <li>名前:<input type="text" v-model="firstName" ></li>
      <li>フルネーム:{{ fullName }}</li>
    </ul>
  </div>
</template>

<script>
export default {
  data(){
    return{
      lastName: '',
      firstName: '',
      fullName: '',
    }
  },
  watch:{
    lastName: function(){
      this.fullName = this.lastName + " " + this.firstName
    },
    firstName: function(){
      this.fullName = this.firstName + " " + this.lastName
    }
  }
}
</script>

<style scoped>
  #user-detail{
    margin: 0 auto;
    width: 800px;
    border: 10px solid red;
  }
  .profile-list{
    margin: 40px auto;
    padding-left: 200px; 
    text-align: left;
  }
</style>

以上で設定は完了です。


ブラウザの表示

ブラウザの表示は以下のようになります。

 ↓ 苗字と名前を入力

watchが機能してフルネームが自動で返されます。


コンポーネント読み込み時にidやclass、v-bindを指定する

コンポーネント読み込み時にidやclass、v-bindを指定することもできます。

コンポーネント名の後ろに、スペースを開け(あるいは改行して)、それぞれの属性と値を記述します。

<コンポーネント名
 id="unique-id"
 class="class-name"
 :class="プロパティ名"
 .... />

同様の手順でv-on(@)やv-modelも指定できます。


実例

例えば、HelloWorld.vueの中で「UserDetail」というコンポーネントを読み込み、コンポーネント読み込み時にidやclassを指定する場合は以下のようになります。

<template>
  <div class="hello">
    <UserDetail 
     id="testId"
     class="testClass"
     :class="originalClass"
    />
    省略(デフォルトのまま)
  </div>
</template>

<script>
import UserDetail from './UserDetail'

export default {
  name: 'HelloWorld',
  components: {
    UserDetail
  },
  props: {
    msg: String
  },
  data(){
    return{
      originalClass: 'my-class'
    }
  }
}
</script>

<!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped>
h3 {
  margin: 40px 0 0;
}
ul {
  list-style-type: none;
  padding: 0;
}
li {
  display: inline-block;
  margin: 0 10px;
}
a {
  color: #42b983;
}
</style>


ブラウザの表示

コンパイル後のブラウザの表示は以下のようになります。

ソースコードを確認すると、以下のようにテンプレートを囲む最上位のタグに、指定したidやクラス名が入っているのがわかります。

<div id="user-detail" class="testClass my-class" data-v-b7412fa8="" data-v-469af010="">
  <h1 data-v-b7412fa8="">ユーザーの詳細ページです</h1>
  <ul class="profile-list" data-v-b7412fa8="">
    <li data-v-b7412fa8="">苗字:<input type="text" data-v-b7412fa8=""></li>
    <li data-v-b7412fa8="">名前:<input type="text" data-v-b7412fa8=""></li>
    <li data-v-b7412fa8="">フルネーム:</li>
  </ul>
  <p data-v-b7412fa8=""></p>
</div>


親コンポーネントのデータを子コンポーネントに渡す方法

idやclass以外にも、親コンポーネントでdataの中に定義してあるプロパティ(変数)を子コンポーネントの中で使いたいときがあります。

親コンポーネントの中の記述

その場合は、親コンポーネントの中の子コンポーネントタグの中に以下を記述します。

<子コンポーネント名 :渡すプロパティ名="プロパティ名" />

改行もできます。複数設置する場合は改行するのが一般的です。

<子コンポーネント名
  :渡すプロパティ名1="プロパティ名1"
  :渡すプロパティ名2="プロパティ名2"
  :渡すプロパティ名3="プロパティ名3"
 ,,, />
point

値として指定するプロパティ名と、子コンポーネントに渡すプロパティ名を一致させる必要はありませんが、同じにするのが一般的です。

子コンポーネントでは渡されたプロパティ名をpropsオブジェクトの中で定義します。


実例

例えば、dataで「xxx」という名前で定義しているデータを子テンプレート「UserDetail」に「xxx」という名前で渡す場合は以下のようになります。

(※データの値と渡すプロパティ名は同じである必要はありません。)

<template>
  <div class="hello">
    <UserDetail 
     :xxx="xxx"
    />
    <div>xxxの値:{{xxx}}</div>
  </div>
</template>

<script>
import UserDetail from './UserDetail'

export default {
  name: 'HelloWorld',
  components: {
    UserDetail
  },
  data(){
    return{ 
      xxx: "secret"
    }
  }
</script>

<style scoped>
省略
</style>


子コンポーネントの中の記述

子コンポーネントでは渡されたデータを使えるようにするためにpropsオブジェクトの中でそのデータを指定する必要があります。

<script>
export default {
  props:{
    渡されたプロパティ名: 型
  },
  (省略)
}
</script>
注意点

渡されたプロパティ名には、型の指定やデフォルト値の設定、受け渡しの必須などバリデーション指定できます。

何もない場合は、「undefined」や「{}」を値に設定する必要があります。

これらがないとエラーが発生するので注意してください。詳細は下記をご参考ください。

【Vue】propsのtypeとは何か?プロパティ設定時の注意点と使い方を実例で解説|type, default, required, validation


実例

親コンポーネントから「:xxx=”プロパティ名”」として渡されたデータを、子コンポーネントで受け取り、型で文字列を指定する場合は以下のようになります。

<template>
  <div id="user-detail">
    <h1>ユーザーの詳細ページです</h1>
    <ul class="profile-list">
      <li>親コンポーネントから受け取ったデータ: {{ xxx }} </li>
    </ul>
    <p></p>
  </div>
</template>

<script>
export default {
  props:{
    xxx: {type: String}
  }
}
</script>

<style scoped>
省略
</style>

propsで定義したことにより、templateタグの中でプロパティとして呼び出すことができるようになります。

<li>親コンポーネントから受け取ったデータ: {{ xxx }} </li>


親子間のデータの受け渡し

上記は親コンポーネントのデータを子コンポーネントに渡すだけでしたが、状況によっては、コンポーネントの中で、親コンポーネントから受け取ったデータを変更したい場合があります。

そのときは、propsで定義したプロパティを、v-modelで編集したくなりますが、これをするとエラーが発生します。

親子間でのデータの受け渡しには、computedプロパティを使ってゲッターとセッターをセットするといった処理が必要になります。

詳細については下記をご参考ください。

【Vue】propsのデータを変更する方法|Avoid mutating a prop directlyエラーの発生原因と対処法

タイトルとURLをコピーしました