[클론 코딩] Nuxt3 웹 사이트 만들기(Quasar를 이용한 UI 구현) - 2편
안녕하세요. 기깔나는 사람들에서 프론트엔드를 맡고있는 해리입니다.
저번편에선 프로젝트 초기 구성과 개발에 들어가기에 앞서 테스트 및 상태 관리 라이브러리 등을 구성하였습니다!
[클론 코딩] 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>
실행된 화면입니다! 레이아웃이 정상적으로 표시되는 것을 확인하실 수 있습니다!
전역 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 파일 생성)
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개의 컴포넌트를 생성해줍니다.
로고 및 회사, 서비스 관련 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를 구현해보겠습니다!
끝까지 읽어주셔서 감사합니다 :)