[클론 코딩] Nuxt3 웹 사이트 만들기(Quasar를 이용한 UI 구현) - 2편

2023. 7. 5. 14:50초기 과업/FrontEnd

작성자알 수 없는 사용자

728x90
반응형

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

저번편에선 프로젝트 초기 구성과 개발에 들어가기에 앞서 테스트 및 상태 관리 라이브러리 등을 구성하였습니다!

 

 

[클론 코딩] Nuxt3 + Firebase 를 이용한 웹 사이트 구현하기 - 1편

안녕하세요! 기깔나는 사람들에서 프론트엔드을 맡고 있는 해리입니다! 신규 프로젝트에 들어가기 전 팀원분과 클론 코딩이란 주제로 미소(https://miso.kr/deepclean) 웹 사이트를 구현하게되었습니

giggal-people.tistory.com

 

이번편에서는 Quasar 를 이용해 미소(https://miso.kr/deepclean) 웹 사이트의 레이아웃을 구현해보겠습니다!

 

 


기본 레이아웃 구현

nuxt 에서 제공하는 layouts 폴더를 이용하여 기본적인 골격을 구현해 보겠습니다.

 

먼저 layout 사용을 위해 app.vue 파일에 NuxtPage를 NuxtLayout 태그로 감싸줍니다.

<template>
  <div>
    <NuxtLayout>
      <NuxtPage />
    </NuxtLayout>
  </div>
</template>

 

1편에서 추가한 layouts 폴더안에 default.vue 파일을 생성해줍니다. pages 폴더에 생성한 파일들은 layout 이 설정되어있지않으면 기본적으로 default 레이아웃을 사용합니다. slot 태그를 통해 부모 컴포넌트에서 전달한 Page 요소를 header와 footer 중간에 표시되도록했습니다. 

q-header, q-page-container 등 "q-" 은 quasar 컴포넌트입니다.

<template>
  <!-- header  -->
  <q-header>header 영역</q-header>

  <!-- body  -->
  <q-page-container>
  	<q-page>
        <slot />
    </q-page>

  	<!-- footer  -->
  	<q-footer>footer 영역</q-footer>
  </q-page-container>
</template>

 

실행된 화면입니다! 레이아웃이 정상적으로 표시되는 것을 확인하실 수 있습니다!

localhost:3000

 


전역 SCSS 변수 등록

UI 구현에 앞서 이번 프로젝트에서는 Scoped CSS 를 사용하여 각 페이지, 컴포넌트안에 독립전인 CSS 를 작성할 예정입니다!

이렇게한 이유 중 하나는 모든 페이지의 요소들을 컴포넌트화하여 유지보수에 용이하도록 하기 위해서입니다. 중복적으로 사용하는 스타일값들은 전역적으로 선언하여 사용하려고합니다.

 

sass 설치하기

yarn add --dev sass

 

assets 폴더에 common.scss 파일 추가하기

테스트를 위해 common.scss 파일에 primary 색상 변수를 작성해주었습니다.

$primary: #055cf5;

 

전역 파일 등록

nuxt.config.ts 파일에 아래 설정을 추가해주면 이제 common.scss 에 선언한 변수들을 페이지 및 컴포넌트들에서 import 없이 사용할 수 있습니다! 

export default defineNuxtConfig({
	// ...
    vite: {
    	css: {
        	preprocessorOptions: {
            	scss: {
                	additionalData: '@import "@/assets/common.scss";',
                },
            },
        },
    },
});

 


Header

components 폴더에 Header.vue 컴포넌트를 생성합니다.

아래는 미소 웹 페이지에 Header 영역입니다. 빨간색 테두리는 Header 안의 Container 영역으로 파란색 테두리는 기능에 따라 분리한 것으로 로고와 메뉴 목록을 컴포넌트화 해줍니다. (.vue 파일 생성)

미소 Header 영역

Logo Component

<template>
  <nuxt-link to="/">
    <img src="~/assets/images/logo.png" class="logo" />
  </nuxt-link>
</template>

<style lang="scss">
.logo {
  width: 70px;
  height: auto;
}
</style>

 

GlobalNavigation Component

메뉴는 하드코딩된 상수값을 이용하여 반복문을 돌려줍니다.

// 메뉴 목록
import { GlobalMenu } from "~/types/menu";

export const MENUS: GlobalMenu[] = [
  {
    key: "global-menu-1",
    name: "이사·이사청소",
    children: [
      { key: "global-menu-1-1", name: "이사" },
      { key: "global-menu-1-1", name: "입주/이사청소" },
      { key: "global-menu-1-1", name: "인터넷 가입" },
    ],
  },
  { key: "global-menu-2", name: "파트너 지원", children: [] },
  { key: "global-menu-3", name: "고객센터", children: [] },
];
<template>
  <div class="nav">
    <q-btn
      v-for="menu in MENUS"
      :key="menu.key"
      :label="menu.name"
      class="nav-item"
    >
      <q-menu v-if="menu.children.length > 0">
        <q-list style="min-width: 100px">
          <q-item
            v-for="children in menu.children"
            :key="children.key"
            clickable
            v-close-popup
          >
            <q-item-section>{{ children.name }}</q-item-section>
          </q-item>
        </q-list>
      </q-menu>
    </q-btn>
  </div>
</template>

<script lang="ts">
import { MENUS } from "~/const/menu";

export default defineComponent({
  setup() {
    return { MENUS };
  },
});
</script>

<style lang="scss">
.nav {
  flex: 1;
  display: flex;
  justify-content: flex-end;
  height: 100%;
}
.nav-item {
  height: 100%;
  padding: 0 20px;
  color: #000;
  border-radius: 0;
}
.nav-item::before {
  box-shadow: none;
}
.nav-item:hover::before {
  border-bottom: solid $primary 3px;
}
.nav-item:hover {
  color: $primary;
}
.q-focus-helper {
  background-color: #fff !important;
}
</style>

 

Header Component

그리고 Header Component 안에 생성한 로고와 메뉴 목록 컴포넌트를 불러와줍니다.

<template>
  <q-header>
    <div class="h-container">
      <!-- 메인 로고 이미지 -->
      <LogoLink />

      <!-- 상단 전역 메뉴 목록 -->
      <GlobalNavigation />
    </div>
  </q-header>
</template>

<script lang="ts">
import LogoLink from "~/components/common/header/LogoLink.vue";
import GlobalNavigation from "~/components/common/header/GlobalNavigation.vue";

export default {
  components: { LogoLink, GlobalNavigation },
};
</script>

<style lang="css">
.q-header {
  background-color: #fff;
  position: fixed;
}
.h-container {
  display: flex;
  width: 75%;
  height: 80px;
  margin: 0 auto;
  padding: 5px 0;
  align-items: center;
}
</style>

 

이제 default Layout 에 Header Component 를 바꿔주기만하면 끝입니다!

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

    <!-- body  -->
    <q-page-container>
    	<q-page>
        	<slot />
        </q-page>
        
        <!-- footer  -->
        <q-footer>footer 영역</q-footer>
    </q-page-container>
  </q-layout>
</template>

<script lang="ts">
import LayoutHeader from "~/components/layout/LayoutHeader.vue";

export default { components: { LayoutHeader } };
</script>

 

Header 완성!

미소 클론 사이트

 


Footer

이번엔 Footer 작업을 위해 Footer.vue 컴포넌트를 생성합니다.

 

저는 로고, 회사 및 서비스 관련 정보/카피라이트 이렇게 2가지 영역으로 나누려고 합니다!

2개의 컴포넌트를 생성해줍니다.

미소 Footer 영역

 

로고 및 회사, 서비스 관련 Component

<template>
  <div class="logo-wrap">
    <img src="~/assets/images/logo-white.png" class="logo-white" />
  </div>
  <q-list class="elementor-column-group">
    <q-item
      class="elementor-column"
      href="https://blog.naver.com/misomktblog"
      target="_blank"
    >
      블로그
    </q-item>
    <q-item
      class="elementor-column"
      href="https://miso.kr/public/terms/tos.html"
      target="_blank"
    >
      이용약관
    </q-item>
    <q-item
      class="elementor-column"
      href="https://miso.kr/public/terms/privacy.html"
      target="_blank"
    >
      개인정보
    </q-item>
  </q-list>
</template>

<style lang="css">
.logo-wrap {
  flex: 1;
}
.logo-white {
  width: 80px;
  height: auto;
}
.q-list.elementor-column-group {
  display: flex;
  font-weight: bold;
  font-size: 15px;
}
.q-list.elementor-column-group .q-item.elementor-column {
  padding: 20px;
}
.q-list .q-item .q-focus-helper,
.q-list .q-item .q-focus-helper:after {
  background: none !important;
}
</style>

 

카피라이트 Component

<template>
  <q-list class="copyright">
    <q-item>© 유한회사 미소. Miso, Inc. All Rights Reserved.</q-item>
    <q-item>
      사업자등록번호 : 291-87-00271 | 인허가번호 : 2016-3220163-14-5-00019 |
      대표이사 : CHING VICTOR COLUMBIA R | 전화 : 1577-8808 | 주소 : 서울시
      강남구 논현로 86길 32, 1층
    </q-item>
    <q-item><div>언론 보도 관련 문의: contact@getmiso.com</div></q-item>
  </q-list>
</template>

<style lang="css">
.q-list.copyright {
  color: #a3a7ae;
}
.q-list.copyright .q-item {
  min-height: 0;
  padding: 0;
  line-height: 1.5;
}
</style>

 

Footer Component

마지막으로 Footer Component에 두 컴포넌트를 넣어줍니다.

<template>
  <q-footer>
    <div class="f-container">
      <!-- 로고 및 회사, 서비스 관련 정보 -->
      <div class="footer-row">
        <company-link />
      </div>

      <!-- 저작권 -->
      <div class="footer-row">
        <copyright />
      </div>
    </div>
  </q-footer>
</template>

<script lang="ts">
import CompanyLink from "~/components/common/footer/CompanyLink.vue";
import Copyright from "~/components/common/footer/Copyright.vue";

export default { components: { CompanyLink, Copyright } };
</script>

<style lang="css">
.q-footer {
  background-color: #2e3035;
}
.f-container {
  width: 75%;
  padding: 22px 0px 48px 0px;
  margin: 0 auto;
}
.footer-row {
  display: flex;
  align-items: center;
  margin-top: 10px;
}
</style>

 

마지막으로 default Layout 도 마찬가지로 footer 부분을 Footer Component 로 교체해주면 아래와 같이 레이아웃 UI  작업이 끝이났습니다! ! 👏🏻👏🏻👏🏻

 

미소 클론 사이트


이번편에서는 기본적인 레이아웃 UI 구현을 위주로 작성했습니다.

다음 편에서는 페이지 생성 및 NuxtLink 컴포넌트를 이용한 페이지 이동과 나머지 화면 UI를 구현해보겠습니다!

 

끝까지 읽어주셔서 감사합니다 :)


 

 

 

 

728x90
반응형