WebDesigner's Memorandumウェブデザイナーの備忘録

Nuxt.jsでコンポーネントを作成してコードの共通化を行う|Nuxt.jsの基本

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>

著者について

プロフィール画像

サイトウ マサカズ@31mskz10

1997年生まれ。2016年から専門学校でデザインについて勉強。卒業後は神戸の制作会社「N'sCreates」にウェブデザイナーとして入社。このブログでは自分の備忘録も兼ねて、ウェブに関する記事や制作環境を効率的に行うための記事を書いています。

Twitterをフォロー Facebookでいいね