Nuxt.jsでレスポンシブのメニューを作成する方法
Nuxt.jsでレスポンシブのメニューを作成する方法を紹介します。
目次から読む
Nuxt.jsでレスポンシブのメニューを作成する方法
作成イメージ
ディレクトリ構造
root
├─ src
├─ components
│ ├─ Navigation
│ │ ├─ TheHeader.vue
│ │ ├─ TheSidenav.vue
│ │ └─ TheSideNavToggle.vue
├─ layouts
│ ├─ default.vue
├─ pages
│ ├─ about
│ │ ├─ index.vue
│ ├─ admin
│ │ ├─ index.vue
│ ├─ posts
│ │ ├─ index.vue
手順
- Navigationのコンポーネントを作成
- レスポンシブメニューを表示させたいレイアウトにNavigationのコンポーネントを記述する
- styleではnuxt-link-activeクラスを付与する
Navigationのコンポーネントは、ヘッダー部分(TheHeader.vue)とサイドバーを表示非表示に切り替えるハンバーガー部分(TheSideNavToggle.vue)、そしてサイドバー部分(TheSidenav.vue)を作成します。
TheHeader.vue
<template>
<div class="header-container">
<header class="the-header">
<!-- ハンバーガー(768px以上で非表示) -->
<TheSideNavToggle @toggle="$emit('sidenavToggle')" />
<div class="logo">
<nuxt-link to="/">タイトル</nuxt-link>
</div>
<!-- スペース -->
<div class="spacer"></div>
<!-- ナブアイテム(768px未満で非表示) -->
<div class="navigation-items">
<ul class="nav-list">
<li class="nav-item"><nuxt-link to="/posts">ブログ</nuxt-link></li>
<li class="nav-item"><nuxt-link to="/about">アバウト</nuxt-link></li>
<li class="nav-item"><nuxt-link to="/admin">管理画面</nuxt-link></li>
</ul>
</div>
</header>
</div>
</template>
templateでは、ハンバーガー、タイトル、ナブアイテムをセットします。
ハンバーガーとナブアイテムはメディアクエリで表示を切り替えます。
<script>
import TheSideNavToggle from "@/components/Navigation/TheSideNavToggle";
export default {
name: "TheHeader",
components: {
TheSideNavToggle
}
};</script>
サイドバーの切替には、トグルできるコンポーネントを作成します。
<style scoped>
.header-container {
height: 60px;
}
.the-header {
width: 100%;
position: fixed;
height: 60px;
display: flex;
justify-content: space-around;
align-items: center;
background: linear-gradient(to right, #0f2027, #203a43, #2c5364);
z-index: 100;
box-sizing: border-box;
padding: 0 20px;
}
.logo {
margin: 0 10px;
font-size: 1.3rem;
}
.logo a {
text-decoration: none;
color: white;
}
.spacer {
flex: 1;
}
.navigation-items {
display: none;
}
@media (min-width: 768px) {
.navigation-items {
display: block;
}
}
.nav-list {
list-style: none;
padding: 0;
margin: 0;
display: flex;
}
.nav-item {
margin: 0 10px;
}
.nav-item a {
text-decoration: none;
color: white;
}
/* nuxt-link-activeでアクティブクラスをハイライト */
.nav-item a:hover,
.nav-item a:active,
.nav-item a.nuxt-link-active {
color: #f7797d;
}</style>
現在表示されているリンクに色をつけたり特定のスタイルを適用させたい場合、
nuxt-link-activeクラスを付与することで実現できます。
TheSidenav.vue
<template>
<div class="sidenav-container">
<!-- サイドバーのバックドロップ背景 -->
<div
v-if="show"
class="sidenav-backdrop"
@click="$emit('close')"></div>
<!-- トランジション -->
<transition name="slide-side">
<!-- サイドナブ -->
<div
v-if="show"
class="sidenav">
<div
class="drawer-toggle"
role="button"
@click="$emit('close')">
<div class="bar"></div>
<div class="bar"></div>
</div>
<!-- ハンバーガーメニュー -->
<ul
class="nav-list"
@click="$emit('close')">
<li class="nav-item"><nuxt-link to="/posts">ブログ</nuxt-link></li>
<li class="nav-item"><nuxt-link to="/about">About</nuxt-link></li>
<li class="nav-item"><nuxt-link to="/admin">管理画面</nuxt-link></li>
</ul>
</div>
</transition>
</div>
</template>
<script>
export default {
name: "TheSidenav",
props: {
show: {
type: Boolean,
default: false
}
}
}</script>
<style scoped>
.sidenav-container {
height: 100%;
width: 100%;
}
.sidenav-backdrop {
width: 100%;
height: 100%;
background-color: rgba(0, 0, 0, 0.7);
z-index: 1000;
position: fixed;
top: 0;
left: 0;
}
.sidenav {
height: 100%;
width: 300px;
background-color: white;
z-index: 10000;
position: fixed;
top: 0;
left: 0;
box-sizing: border-box;
padding: 30px;
}
.slide-side-enter-active,
.slide-side-leave-active {
transition: all 0.3s ease-out;
}
.slide-side-enter,
.slide-side-leave-to {
transform: translateX(-100%);
}
.nav-list {
list-style: none;
padding: 0;
margin: 0;
}
.nav-item {
margin: 20px 0;
}
.nav-item a {
text-decoration: none;
color: black;
font-size: 1.5rem;
}
.nav-item a:hover,
.nav-item a:active,
.nav-item a.nuxt-link-active {
color: #f7797d;
}
.drawer-toggle {
display: flex;
flex-direction: column;
justify-content: space-around;
height: 35px;
width: 35px;
cursor: pointer;
}
.bar {
height: 2px;
background: black;
transition: all 0.3s ease-in-out 0.5s;
}
.bar:nth-child(1) {
transform: rotate(135deg) translateY(-10px);
transform-origin: bottom;
}
.bar:nth-child(2) {
transform: rotate(-135deg) translateY(10px);
transform-origin: top;
}</style>
TheSideNavToggle.vue
このコンポーネントは、ハンバーガーメニューの部分です。
TheHeader.vueにインポートして使います。
<template>
<!-- ハンバーガーメニュー -->
<div
class="drawer-toggle"
role="button"
@click="$emit('toggle')">
<div class="bar"></div>
<div class="bar"></div>
<div class="bar"></div>
</div>
</template>
<style scoped>
.drawer-toggle {
display: flex;
flex-direction: column;
justify-content: space-around;
height: 50%;
width: 35px;
cursor: pointer;
}
@media (min-width: 768px) {
.drawer-toggle {
display: none;
}
}
.drawer-toggle .bar {
width: 90%;
height: 2px;
background-color: white;
}</style>
default.vue
次にレイアウトに組み込みます。
トグルするTheSideNavToggle.vueはTheHeader.vueにすでに組み込んであるので、
TheHeaderとTheSidenavをインポートします。
<template>
<div>
<TheHeader @sidenavToggle="displaySidenav = !displaySidenav" />
<TheSidenav :show="displaySidenav" @close="displaySidenav = false" />
<Nuxt />
</div>
</template>
サイドバーを表示・非表示を切り替えたいので、displaySidenavという変数を用意して、true/falseで切り替えます。
<script>
import TheHeader from '@/components/Navigation/TheHeader'
import TheSidenav from '@/components/Navigation/TheSidenav'
export default {
components: {
// Header,
TheHeader,
TheSidenav,
},
data() {
return {
displaySidenav: false,
}
}
}</script>
あとは、pagesの各ページを作成すればOKです。