Nuxt.jsでコンポーネントを作成してコードの共通化を行う|Nuxt.jsの基本
Nuxt.jsでもコンポーネントが作成できて、作り方はVue CLIとほとんど同じになります。
今回はNuxt.jsのコンポーネントの基本的な部分をまとめておきます。
コンポーネントファイルの作成
コンポーネントファイルは「/components」フォルダ内に作成します。
今回は例として、ボタン用のコンポーネントの「/components/PrimaryButton.vue」を作成します(コンポーネントの名前はパスカルケースで書きます)。
PrimaryButton.vue内には<template>
内にHTML、<style>
内にCSS、<script>
内にJavaScript(Vue.js)を書いて、ボタンに関するすべてがファイル1つにまとまっている状態になります。
このように1つのコンポーネントに対するHTML・CSS・JavaScriptを1ファイルにまとめることを「単一ファイルコンポーネント」と呼びます。
<template>
<!-- HTMLを記述 -->
</template>
<style scoped>
/* CSSを記述 */
</style>
<script>
export default {
//JavaScript(Vue.js)を記述
}
</script>
template内の記述
コンポーネントのHTML要素を記述していきます。
ルールとして、必ず<template>
直下はHTMLタグが1つとなる必要があります。
下記は<template>
直下に<button>
と<p>
が2つあるので、この場合はエラーになってしまいます。
<template>
<button @click="onClickButton">{{buttonText}}</button>
<p>{{smallText}}</p>
</temaplte>
下記のように、<div>
で囲って<template>
直下がHTMLタグ1つになればOKです。
<template>
<div>
<button @click="onClickButton">{{buttonText}}</button>
<p>{{smallText}}</p>
</div>
</temaplte>
style内の記述
CSSの記述をしますが、<style scoped>
とすることで、その中で指定したCSSはこのコンポーネントにのみ適用されるようにできます。
通常のウェブサイトではCSSが他の場所に影響しないようにclass名を工夫したり、被らないように親要素にclassを用意して…などしますが、その必要はなくなります。
class名もシンプルなものが使えたり、タグ名をそのまま指定することも許されます。
逆にscoped
がないと、サイト全体に影響が出るので注意が必要です。
scriptの記述
Vue.jsの記述をしますが、通常のVue.jsと変わりません。
dataは関数として定義する必要があるので、そこだけ注意しましょう。
<script>
export default {
data: () => ({
}),
metdhos: {
onClickButton() {
console.log('click')
},
}
}
</script>
コンポーネントファイルの読み込み
コンポーネントファイルはimportでインポートするのと、export default
内のcomponents:{}
で指定します。
あとは<template>
内でケバブケースに変換した状態でHTMLタグとして記述します。
<template>
<primary-button></primary-button>
</template>
<script>
import PrimaryButton from '~/components/PrimaryButton'
export default {
components: {
PrimaryButton,
},
}
</script>
さらに高度なscriptの設定
プロパティの設定
コンポーネントではオプションオブジェクトにプロパティ(props)を渡して、それを使って処理を書きます。
script内にキャメルケースでprops
内にプロパティ名と、その定義をします(必須ではないですが、予期せぬエラーを防げます)。
定義 | 内容 | 備考 |
---|---|---|
type | プロパティのデータ型 | String(文字列) / Number(数字) / Boolean(真偽値) / Array(配列) / Object(オブジェクト) |
default | プロパティの指定がなかった場合のデフォルト値 | |
required | プロパティの指定が必須かどうか | trueかfalseを指定 |
validation | プロパティのバリデーション関数 |
<script>
export default {
props: {
backgroundColor: {
type: String,
default: '#00f'
}
}
}
</script>
script内のmethodsなどの他の場所で使用するときは「this.buttonText
」のようにして扱います。
template内で使用するときは名前そのまま波括弧2つで「{{buttonText}}
」のようにするとテキストとして出力されます。
属性内で使用したい場合は、属性名の最初に「:(コロン)」が付いている状態で名前そのまま「:href="link"
」のようにして入力します(「href="link"
」だと「link
」という文字列そのまま出力されてしまうため、プロパティから引っ張ってこられない)。
データで動的に変わる属性は「:(コロン)が付く」と覚えておきましょう。
コンポーネント読み込み時にpropsにデータを渡す
コンポーネント読み込み時にprops名をキャメルケースからケバブケースにして属性名として設定します。
<template>
<primary-button background-color="#f00"></primary-button>
</template>
これも変数などを渡す場合は場合は「:background-color
」のように先頭に「:(コロン)」を付けます。
$emit
$emit
を使うと、親ページにデータを渡したり、イベントが発火したことを親ページに知らせられます。
例えばボタンコンポーネント内のボタンをクリックしたときに、クリックされたことを親ページに知らせて、そこから先の処理は親ページで行えます。
methods: {
onClickButton() {
this.$emit('button-click')
}
}
親ページでは$emit
の第一引数の名前の先頭に「@」を付けて、関数名を指定します(この関数はもちろん親ページ内の関数です)。
<primary-button @button-click="onChangePage"></primary-button>
図にすると下記のような流れになります。
slot
ボタンに表示するテキストなど、コンポーネント内のHTMLをそのまま親要素から指定できます。
また、<slot>
内に入力した要素にはデフォルトの表示を設定できます(空でも問題ありません)。
<template>
<button @click="onClickButton">
<slot>何も入力されていない場合のデフォルト表示</slot>
</button>
</template>
コンポーネント読み込み時にコンポーネントタグで囲った要素が、<slot>
内に表示されます。
<template>
<primary-button">ボタンテキスト</primary-button>
</template>