0
0

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 3 years have passed since last update.

【Nuxt.js】ハンバーガーボタンとグロナビを実装する

Last updated at Posted at 2021-04-27

#■目的
勉強のためNuxt.jsのサンプル集を作る

##目標1
ハンバーガーボタンとグローバルナビを実装する

##ざっくり仕様

  • ハンバーガーボタンはクリックしたら「×」になる
  • スマホ閲覧時グローバルナビを展開したらするるっとアニメーションする
  • グローバルナビのHTMLはPC・スマホ1ソースで行きたい
  • わかる範囲内でアトミックデザインを意識する

##default.vue
まずはベースファイルとして以下を用意する。

layouts/default.vue
<template>
  <div>
    <HtmlHeader />
    <div id="wrap">
      <Nuxt />
    </div>
    <HtmlFooter />
  </div>
</template>

<script>
import HtmlHeader from '@/components/organisms/HtmlHeader.vue'
import HtmlFooter from '@/components/organisms/HtmlFooter.vue'

export default {
  components: {
    HtmlHeader,
    HtmlFooter
  }
}
</script>

今回はcomponents/organismsの中にHtmlHeader.vueというコンポネントを作成し、
そのコンポネントの中でハンバーガーボタンとグロナビのファイルを読み込む。
(と、いうのはどうだろうか、という話で実はまだいろいろ迷ってる)

##HtmlHeader.vue
ここでボタンやリストを読み込んで、クリックした際のイベントとか書く
(で、あってるんだろうか、という話できっともっと良い方法たくさんある)

components/organisms/HtmlHeader.vue
<template>
  <header id="header">
    <div class="header__inner">
      <h1>Header</h1>
      <BtnHamburger
        :class="{active : gnaviOn}"
        @btnMenu="toggleMenu"
      />
    </div>
    <transition
      @before-enter="beforeEnter"
      @enter="enter"
      @before-leave="beforeLeave"
      @leave="leave"
    >
      <nav
        v-if="gnaviOn"
        class="gnavi"
      >
        <NaviList />
      </nav>
    </transition>
  </header>
</template>

<script>
import BtnHamburger from '@/components/atoms/buttons/hamburger'
import NaviList from '@/components/molecules/lists/navilist'

export default {
  components: {
    BtnHamburger,
    NaviList
  },
  data () {
    return {
      gnaviOn: false
    }
  },

  methods: {
    toggleMenu () {
      this.gnaviOn = !this.gnaviOn
    },
    beforeEnter (el) {
      el.style.height = '0'
    },
    enter (el) {
      el.style.height = el.scrollHeight + 'px'
    },
    beforeLeave (el) {
      el.style.height = el.scrollHeight + 'px'
    },
    leave (el) {
      el.style.height = '0'
    }
  }
}
</script>
※cssは省略

##BtnHamburger
これはatomsか? ということで。クリックしたらemitで渡す。

components/atoms/buttons/hamburger.vue
<template>
  <div class="btn-hamburger" @click="btnMenu">
    <span />
    <span />
    <span />
  </div>
</template>

<script>
export default {
  methods: {
    btnMenu () {
      this.$emit('btnMenu')
    }
  }
}
</script>
※cssは省略

##NaviList
将来的に追記しなければないようなケースが発生するかもしれないけれど、
それはそれでその時考える。初回はシンプルに行きたい。
(これ、もっと分解して配列で処理すべきだよな、と……)

components/molecules/lists/navilist.vue
<template>
  <ul class="navilist">
    <li>
      <Nuxt-link to="/">
        Home
      </Nuxt-link>
    </li>
    <li>
      <Nuxt-link to="/information/">
        Information
      </Nuxt-link>
    </li>
    <li>
      <Nuxt-link to="/about/">
        About us
      </Nuxt-link>
    </li>
    <li>
      <Nuxt-link to="/contact/">
        Contact
      </Nuxt-link>
    </li>
  </ul>
</template>
※cssは省略

##結果
さぁ、これでOK! と思い確認。
SP版OK。ちゃちゃっと書いたcssもいい感じできれいに見せてくれてる!
と、思ったらPCで確認したときにおかしくなり、一つ忘れていることがありました。

components/organisms/HtmlHeader.vue
<nav
  v-if="gnaviOn"
  class="gnavi"
>
  <NaviList />
</nav>

このv-ifの書き方だと、PCでNaviListが表示されない。
最初に書いたとおり、2ソース書いてcssのメディアクエリで表示/非表示の切り替え、
みたいなことはやりたくないしなぁ、と少し悩みます。

いろいろ難しいなぁ。
と、いうことで調べてしらべて、改善案。

0
0
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
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?