116
105

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

【Nuxt.js】layoutsに設定をまとめつつ、タイトルはpagesから設定したい

Last updated at Posted at 2019-07-08

これって、Qiita記事の種になりませんか?

つまり、こういうことになります

  • /layoutsにヘッダーのコンポーネントを含めつつ
  • /pagesのファイルから/layoutsで使用しているコンポーネントの値を設定する(値を渡す)

基本構成

  • レイアウト内でヘッダーコンポーネントを読み込み、表示している。
  • 上記レイアウトを適用してpagesを表示。
  • layout(components) > pagesの親子関係

フォルダ

/components
  - Header.vue 
/layouts
  - ore.vue
/pages
  - index.vue 

ファイル

components/Header.vue
<template>
  <h1>{{ title }}</h1>
</template>

<script>
export default {
  props: {
    title: {
      type: String,
      default: ''
    }
  }
}
</script>
layouts/ore.vue
<template>
  <div>
    <Header />
    <nuxt />
  </div>
</template>

<script>
import Header from '@/components/Header'

export default {
  components: {
    Header
  }
}
</script>
pages/index.vue
<template>
  <div>
    abc
  </div>
</template>

<script>
export default {
  name: 'sample',
  layout: 'ore'
}
</script>

方法

1. page側から$emitでlayout側に値を渡す。

  1. dataに値を定義。
  2. methodsに$emitで渡すメソッドを定義。
  3. mountedのタイミングで2のメソッドを実行。
pages/index.vue
<template>
  <div>
    abc
  </div>
</template>

<script>
export default {
  name: 'sample',
  layout: 'ore',
  data(){
    return {
      header: {
        title: 'ページタイトル'
      }
    }
  },
  mounted() {
    this.updateHeader()
  },
  methods: {
    updateHeader() {
      // タイトルとして使いたい情報を渡す
      this.$nuxt.$emit('updateHeader', this.header.title)
    }
  }
}
</script>

2. layout側でイベントを受け取るようにする

  • dataにタイトルの初期値を定義。
  • createdのタイミングでイベントリスナーを設定。$nuxt.onで定義する。
  • 要素に@eventNameの形式で記述する形だとmounted以後にしか設定されない。
  • そのため、mounted直後の子要素のイベント発火を検知できなかった。
  • イベントを検知した後、タイトルを書き換える処理を追加。
layouts/ore.vue
<template>
  <div>
    <Header />
    <nuxt />
  </div>
</template>

<script>
import Header from '@/components/Header'

export default {
  components: {
    Header
  },
data() {
    return {
      title: ''
    }
  },
  created() {
    this.setListener()
  },
  methods: {
    setListener() {
      // emitで発火させたイベント名にする
      this.$nuxt.$on('updateHeader', this.setHeader)
    },
    setHeader(title) {
      // 第1引数にはemitで渡した値が入ってくる。
      // 第2引数以降を渡す場合も同様に、それ以降の引数で受け取れる
      this.title = title || ''
    }
  }
}
</script>

3.受け取った値を反映させる

  • レイアウトのHeaderコンポーネントに対し、:propsの名前="dataで定義している値" の記述を追加する
layouts/ore.vue
<template>
  <div>
    <Header :title="title" />
    <nuxt />
  </div>
</template>

...略

最終的なファイルの状態

※コンポーネントは最初と変化なし

components/Header.vue
<template>
  <h1>{{ title }}</h1>
</template>

<script>
export default {
  props: {
    title: {
      type: String,
      default: ''
    }
  }
}
</script>
layouts/ore.vue
<template>
  <div>
    <Header :title="title" />
    <nuxt />
  </div>
</template>

<script>
import Header from '@/components/Header'

export default {
  components: {
    Header
  },
data() {
    return {
      title: ''
    }
  },
  created() {
    this.setListener()
  },
  methods: {
    setListener() {
      this.$nuxt.$on('updateHeader', this.setHeader)
    },
    setHeader(title) {
      this.title = title || ''
    }
  }
}
</script>
pages/index.vue
<template>
  <div>
    abc
  </div>
</template>

<script>
export default {
  name: 'sample',
  layout: 'ore',
  data(){
    return {
      header: {
        title: 'ページタイトル'
      }
    }
  },
  mounted() {
    this.updateHeader()
  },
  methods: {
    updateHeader() {
      this.$nuxt.$emit('updateHeader', this.header.title)
    }
  }
}
</script>

まとめ

  • $nuxt.$emitでイベント発火+親に値を渡す。
  • $nuxt.$on('イベント名')で、イベントと値を受け取る。
  • イベントリスナーはcreatedのタイミングで付与しないとまともにイベントが受け取れない。
  • $nuxtの存在を知らないと設定方法で詰む
  • propsの直接の書き換えは怒られるので、dataでやる。

さらにカスタマイズ

  • $emitで複数渡す場合はlayout側のdataを増やし、コンポーネントのバインドも複数にすればOK。
  • setListenerに複数のイベントリスナーを定義すれば、いろんな更新イベントを受け取れる。
  • 今回はヘッダーしか更新しないからupdateHeaderだけど、複数のコンポーネントを更新するならupdateLayoutになりそう。
    • イベント発火はコンポーネント単位で分割したほうが良い
    • 複数のイベント発火をする処理をupdateLayoutで実行するイメージ

参考文献

116
105
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
116
105

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?