Qiita Teams that are logged in
You are not logged in to any team

Log in to Qiita Team
Community
OrganizationEventAdvent CalendarQiitadon (β)
Service
Qiita JobsQiita ZineQiita Blog
91
Help us understand the problem. What are the problem?

More than 1 year has passed since last update.

posted at

updated at

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

これって、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で実行するイメージ

参考文献

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
91
Help us understand the problem. What are the problem?