[클론코딩] Nuxt3 페이지 공통 레이아웃 구현하기

2023. 8. 10. 11:18초기 과업/FrontEnd

작성자알 수 없는 사용자

728x90
반응형

 

안녕하세요. 기깔나는 사람들에서 프론트엔드를 맡고있는 최재혁입니다.

Nuxt3 레이아웃을 구현하는 작업을 글로 남겨보고자 합니다.

 

 


Nuxt 레이아웃 구성

만약에 페이지 전체에서 단 하나의 layout만 사용한다면 최상단의 존재하는 app.vue의 마크업 및 스크립트 작업을 진행하여도 괜찮습니다.

 

하지만 프로젝트가 커질수록 페이지마다 사용하는 레이아웃이 다를테니 layouts 디렉토리에 레이아웃 컴포넌트를 생성하는 방법으로 진행하겠습니다.

 

1. 루트에(최상단) layouts 디렉토리를 생성합니다.

2. layouts 디렉토리에 default.vue를 생성합니다.

 

Quasar 이용하여 기본 레이아웃 설정하기

default.vue

<template>
  <q-layout>
    <q-header>
    </q-header>

    <q-page-container>
      <router-view></router-view>
    </q-page-container>

    <q-footer>
    </q-footer>
  </q-layout>
</template>

<q-layout> 태그를 이용해 전체를 덮어주고

<q-header> 에는 공통 레이아웃에 상단에 들어갈 컴포넌트를

<q-footer>에는 하단에 들어갈 컴포넌트를 넣어주면 됩니다.

 

<q-page-container> 안에는 <router-view>가 삽입되어 있는데

위와 같이 설정해주면 라우팅에 따라 다른 콘텐츠를 <q-page-container>가 있는 위치에 렌더링 시켜줍니다.

 

그리고 렌더링 할 페이지 template에 렌더링 할 페이지 콘텐츠를 <q-page>태그로 덮어 씌워줘야 합니다.

<template>
  <q-page>
    ...page content...
  </q-page>
</template>

상단 메뉴 구현하기

클론코딩을 진행중인 페이지의 상단에 존재하는 공통 레이아웃 헤더 부분을 어떻게 구현하였는지 설명 드리겠습니다.

 

 


MainMenuItems 컴포넌트 생성하기

페이지에서 제공하는 서비스들의 카테고리를 선택할 수 있는 부분을 컴포넌트로 먼저 생성해주었습니다.

 

컴포넌트를 생성하기에 앞서 menuItemList.ts 파일을 생성하여 카테고리 서비스를 data 폴더에 정리 해주었습니다.

 

manuItemList.ts

export const mainMenuItemList: MainMenuItem[] = [
  {
    label: "가사도우미",
    subMenuItems: [
      { label: "가사도우미", link: "/homeclean" },
      { label: "사무실 청소", link: "/officeclean" },
    ],
  },
  {
    label: "이사ㆍ이사청소",
    subMenuItems: [
      { label: "이사", link: "/moving" },
      { label: "입주/이사청소", link: "/deepclean" },
      { label: "인터넷 가입", link: "/internet" },
    ],
  },
  {
    label: "가전청소",
  },
  {
    label: "다른 홈서비스",
    subMenuItems: [
      { label: "인터넷 가입", link: "/internet" },
      { label: "인테리어", link: "/interior" },
      { label: "전기/수도/가스", link: "/etc" },
      { label: "전문/특수청소", link: "/special" },
      { label: "전체 서비스", link: "/total" },
    ],
  },
  {
    label: "파트너 지원",
  },
  {
    label: "고객센터",
  },
  {
    label: "회사소개",
    subMenuItems: [
      { label: "회사소개", link: "/misoinfo" },
      { label: "팀 문화", link: "/misoculture" },
      { label: "채용공고", link: "/careerboard" },
    ],
  },
];

 

MainMenuItems.vue

 

mainMenuItemList를 가져온 뒤에 v-for 반복문을 통해 자식 컴포넌트인 HeaderSelect 컴포넌트에게 prop으로 각각의 mainMenuitem을 전달하여 메뉴 아이템을 나타내었습니다.

<template>
  <div class="row col-8 justify-between">
    <main-logo />
    <div class="row q-gutter-xl">
      <div v-for="mainMenuItem in mainMenuItemList" :key="mainMenuItem.label">
        <header-select :main-menu-item="mainMenuItem" />
      </div>
    </div>
  </div>
</template>

<script setup lang="ts">
import HeaderSelect from "~/components/HeaderSelect.vue";
import MainLogo from "~/assets/icons/MainLogo.vue";

import { mainMenuItemList } from "~/data/menuItemList";
</script>

 

HeaderSelect.vue

 

prop으로 전달받은 menuItem 객체의 subMenuItem이 존재하면 화살표 모양 아이콘을 렌더링하여 하위 메뉴가 존재한다는 것을 알려주었고 해당 subMenuItem의 label값과 <NuxtLink>를 이용하여 클릭 했을때 라우팅 되도록 해주었습니다.

 

<NuxtLink> 컴포넌트는 Nuxt.js에서 제공하는 내장된 라우터 링크 컴포넌트로, 내부적으로 Vue Router의 <router-link> 컴포넌트를 기반으로 동작합니다.

 

따라서 <NuxtLink>를 사용하면 기본적으로 Vue Router의 <router-link>와 유사한 동작을 하기 때문에, HTML 앵커 태그(<a>)와 비슷한 속성을 활용할 수 있습니다.

<template>
  <div
    class="main-menu-container q-gutter-md"
    @mouseenter="toggleSubMenu"
    @mouseleave="toggleSubMenu"
  >
    <div class="main-menu-item">
      <span class="main-menu-item-label">
        {{ mainMenuItem?.label }}
      </span>
      <ChevronIcon v-if="mainMenuItem?.subMenuItems" />
    </div>
    <div v-if="showSubMenu && mainMenuItem?.subMenuItems" class="submenus-container">
      <ul class="sub-menus q-gutter-md">
        <li v-for="subMenuItem in mainMenuItem.subMenuItems" :key="subMenuItem.label">
          <NuxtLink :to="subMenuItem.link" style="text-decoration: none; color: #2e3035">{{
            subMenuItem.label
          }}</NuxtLink>
        </li>
      </ul>
    </div>
  </div>
</template>

<script setup lang="ts">
import { ref } from "vue";

import ChevronIcon from "../assets/icons/ChevronIcon.vue";

import { MainMenuItem } from "~/types/common";

defineProps({
  mainMenuItem: { type: Object as () => MainMenuItem, default: null },
});

const showSubMenu = ref(false);

const toggleSubMenu = () => {
  showSubMenu.value = !showSubMenu.value;
};
</script>

 

따라서 위에서 생성한 MainMenuItems 컴포넌트를 앞서 설명했던 <q-header> 태그에 자식컴포넌트로 삽입해주면 

<template>
  <q-layout>
    <q-header >
      <q-toolbar >
        <main-menu-items />
      </q-toolbar>
    </q-header>

    <q-page-container>
      <router-view></router-view>
    </q-page-container>

    <q-footer>
    </q-footer>
  </q-layout>
</template>

아래와 같이 컴포넌트가 렌더링 됩니다.


 

 

 

 

 

 

728x90
반응형