๐ฏ ํ์ต ๋ชฉํ
- ๋ฉ๊ฐ๊ณต๋ฌด์ ๋ฉ์ธ ๊ตฌ์กฐ์ ์ ์ฒด ๋ ์ด์์์ Vue ์ปดํฌ๋ํธ๋ก ๋ถ๋ฆฌํ์ฌ ํผ๋ธ๋ฆฌ์ฑํ๋ค.
- ํ๋ฉด ์๋จ๋ถํฐ ํ๋จ๊น์ง์ ๊ณ ์ /์ ๋ ๋ ์ด์์๊ณผ ์ข์ฐ ์ฌ์ด๋, ์ฌ๋ผ์ด๋ ๊ตฌ์กฐ๋ฅผ ๊ตฌํํ๋ค.
๐งฑ ์ค์ต ๊ฐ์
์ด๋ฒ ๊ฐ์์์๋ ๋ค์๊ณผ ๊ฐ์ด ์ ์ฒด ๋ ์ด์์์ ๊ตฌ์ฑํ๊ณ ์ค์ ์ฝ๋๋ก ๊ตฌํํฉ๋๋ค.
Header
: ์๋จ ๊ณ ์ ๋ฉ๋ดLeftQuickMenu
,RightQuickMenu
: ์ข์ฐ ์ฌ์ด๋ ๊ณ ์ ๋ฉ๋ดMainSlide
: ์ข์ธก ์ฝํ ์ธ ์ฌ๋ผ์ด๋MainTabs
: ํญ + ์ฌ๋ผ์ด๋ ์น์ StickyPanel
: ์ฐ์ธก ์ฝํ ์ธ ๊ณ ์ HomePage.vue
: ์ ์ฒด ํ์ด์ง ๋ ์ด์์ ํตํฉ
๐ ์ค์ต ์ฝ๋: HomePage.vue
๋ ์ด์์ ๊ตฌ์ฑ
<template>
<div class="home-page">
<div class="layout-container">
<LeftQuickMenu />
<main class="main-content">
<section class="main-left">
<MainSlide />
<MainTabs />
</section>
<aside class="main-right">
<StickyPanel />
</aside>
</main>
<RightQuickMenu />
</div>
</div>
</template>
<script>
import LeftQuickMenu from "@/components/LeftQuickMenu.vue";
import RightQuickMenu from "@/components/RightQuickMenu.vue";
import MainSlide from "@/components/MainSlide.vue";
import MainTabs from "@/components/MainTabs.vue";
import StickyPanel from "@/components/StickyPanel.vue";
export default {
components: {
LeftQuickMenu,
RightQuickMenu,
MainSlide,
MainTabs,
StickyPanel,
},
};
</script>
<style lang="scss" scoped>
.layout-container {
display: flex;
position: relative;
}
.main-content {
display: flex;
width: 100%;
max-width: 1320px;
margin: 0 auto;
padding: 20px;
}
.main-left {
flex: 3;
display: flex;
flex-direction: column;
gap: 40px;
}
.main-right {
flex: 1;
position: sticky;
top: 100px;
}
</style>
๐งฉ src/assets/base.scss
๋ฉ๊ฐ๊ณต๋ฌด์์ ๋ฒ ์ด์ค scss๋ฅผ ๊ฐ์ ธ์ต๋๋ค.
@import url("https://fonts.googleapis.com/css2?family=Noto+Sans+KR:wght@100;300;400;500;700;900&display=swap");
:root {
--font-noto: "Noto Sans KR";
--font-gothic: "๋ง์ ๊ณ ๋", "Malgun Gothic", "๋์", "Dotum", sans-serif;
--gong-menuIcn-color1: #2642d1;
--gong-menuIcn-color2: #0082ff;
--sobang-menuIcn-color1: #b95253;
--sobang-menuIcn-color2: #ff4141;
--army-menuIcn-color1: #7a8e53;
}
/* reset */
html,
body {
font-family: var(--font-gothic);
font-size: 13px;
color: #000;
letter-spacing: -0.05em;
line-height: 1.3;
margin: 0;
padding: 0;
border: 0;
}
div,
applet,
object,
iframe,
h1,
h2,
h3,
h4,
h5,
h6,
p,
blockquote,
pre,
a,
abbr,
acronym,
address,
big,
cite,
code,
del,
dfn,
em,
img,
ins,
kbd,
q,
s,
samp,
small,
strike,
sub,
sup,
tt,
var,
b,
i,
center,
dl,
dt,
dd,
ol,
ul,
li,
fieldset,
form,
label,
legend,
table,
caption,
tbody,
tfoot,
thead,
tr,
th,
td,
article,
aside,
canvas,
details,
embed,
figure,
figcaption,
footer,
header,
hgroup,
menu,
nav,
output,
ruby,
section,
summary,
time,
mark,
audio,
video {
margin: 0;
padding: 0;
border: 0;
color: inherit;
}
article,
aside,
details,
figcaption,
figure,
footer,
header,
hgroup,
menu,
nav,
section {
display: block;
}
body {
position: relative;
line-height: 1;
}
ol,
ul {
list-style: none;
}
blockquote,
q {
quotes: none;
}
blockquote:before,
blockquote:after,
q:before,
q:after {
content: "";
content: none;
}
table {
border-collapse: collapse;
border: 0;
table-layout: fixed; /*border-spacing:0px; zoom:1; empty-cells:show; width:100%; */
}
th,
td {
word-wrap: break-word;
line-height: 1.3;
padding-left: 3px;
padding-right: 3px;
}
img {
vertical-align: top;
max-width: 100%;
}
input[type="text"],
input[type="password"],
input[type="number"] {
max-width: 100%;
font-family: var(--font-gothic);
}
input[type="checkbox"],
input[type="radio"] {
vertical-align: middle;
position: relative;
margin: 0;
padding: 0;
}
textarea {
font-family: var(--font-gothic) !important;
font-size: 13px;
color: #000;
}
#accessibility,
.skip,
legend,
caption {
position: absolute;
clip: rect(0 0 0 0);
width: 1px;
height: 1px;
margin: -1px;
overflow: hidden;
}
button {
padding: 0;
margin: 0;
border: 0;
background: 0;
line-height: normal;
cursor: pointer;
font-family: var(--font-gothic);
}
button:focus {
outline: none;
}
a {
text-decoration: none;
cursor: pointer;
}
a:link,
a:hover,
a:active {
text-decoration: none;
outline: none !important;
color: inherit;
}
.clearfix {
/**zoom:1*/
}
.f_left {
float: left;
}
.f_right {
float: right;
}
.d_flex {
display: flex;
}
.clearfix:after {
display: block;
content: "";
clear: both;
}
.ellipsis {
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
display: block;
max-width: 90%;
}
.ellipsis2 {
overflow: hidden;
text-overflow: ellipsis;
display: -webkit-box;
-webkit-line-clamp: 2;
-webkit-box-orient: vertical;
}
*:focus {
outline: none;
}
del {
text-decoration: line-through;
color: #aeaeae;
}
.blindw {
position: absolute;
clip: rect(0 0 0 0);
width: 1px;
height: 1px;
margin: -1px;
overflow: hidden;
}
@-webkit-keyframes skeleton-gradient {
0% {
background-color: rgba(165, 165, 165, 0.1);
}
50% {
background-color: rgba(165, 165, 165, 0.3);
}
100% {
background-color: rgba(165, 165, 165, 0.1);
}
}
@keyframes skeleton-line {
100% {
background-position: -100% 0;
}
}
/*layout*/
html {
margin: 0 auto;
}
#mWrap {
position: relative;
}
.darkmask {
position: absolute;
z-index: 9998;
background: #000;
left: 0;
top: 0;
}
/* Noto Sans KR Settings */
.mt10 {
margin-top: 10px;
}
.mb0 {
margin-bottom: 0px !important;
}
.mb30 {
margin-bottom: 30px;
}
/* responsive */
/* [class*="show-"] { display: none !important; } */
.show-1200,
.show-1024,
.show-992,
.show-768,
.show-640,
.show-576,
.show-460 {
display: none !important;
}
@media all and (max-width: 1200px) {
/* responsive */
.hide-1200,
br.hide-1200 {
display: none !important;
}
.show-1200 {
display: inherit !important;
}
.show-1200.block,
br.show-1200 {
display: block !important;
}
.show-1200.flex {
display: flex !important;
}
}
@media screen and (max-width: 1024px) {
/* responsive */
.show-1024 {
display: inherit !important;
}
.show-1024.block,
br.show-1024 {
display: block !important;
}
.show-1024.flex {
display: flex !important;
}
.hide-1024,
br.hide-1024 {
display: none !important;
}
}
@media screen and (max-width: 992px) {
/* responsive */
.show-992 {
display: inherit !important;
}
.show-992.block,
br.show-992 {
display: block !important;
}
.show-992.flex {
display: flex !important;
}
.hide-992,
br.hide-992 {
display: none !important;
}
}
@media screen and (max-width: 768px) {
/* responsive */
.show-768 {
display: inherit !important;
}
.show-768.block,
br.show-768 {
display: block !important;
}
.show-768.flex {
display: flex !important;
}
.hide-768,
br.hide-768 {
display: none !important;
}
}
@media screen and (max-width: 640px) {
/* responsive */
.show-640 {
display: inherit !important;
}
.show-640.block,
br.show-640 {
display: block !important;
}
.show-640.flex {
display: flex !important;
}
.hide-640,
br.hide-640 {
display: none !important;
}
}
@media all and (max-width: 576px) {
/* responsive */
.show-576 {
display: inherit !important;
}
.show-576.block,
br.show-576 {
display: block !important;
}
.show-576.flex {
display: flex !important;
}
.hide-576,
br.hide-576 {
display: none !important;
}
}
@media all and (max-width: 460px) {
/* responsive */
.show-460 {
display: inherit !important;
}
.show-460.block,
br.show-460 {
display: block !important;
}
.show-460.flex {
display: flex !important;
}
.hide-460,
br.hide-460 {
display: none !important;
}
}
๐งฉ src/components/MainSlide.vue
<template>
<div class="main-slide">
<div class="slide-banner">[ ์ฌ๊ธฐ์ ์ฌ๋ผ์ด๋ ๋ฐฐ๋๊ฐ ๋ค์ด๊ฐ๋๋ค ]</div>
</div>
</template>
<style scoped>
.main-slide {
background: #eaf3ff;
height: 300px;
display: flex;
align-items: center;
justify-content: center;
border-radius: 12px;
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.05);
}
</style>
๐งฉ src/components/Header.vue
<template>
<header class="header">
<div class="top-bar">
<div class="top-inner">
<div class="hcode_wrap">
<router-link to="/" class="on">๊ณต๋ฌด์</router-link>
<router-link to="/sobang">์๋ฐฉ</router-link>
</div>
<div class="login_wrap">
<div class="util">
<span class="day">D-100</span>
<router-link to="/academy" class="link">ํ์ ์ ์ฒด๋ณด๊ธฐ</router-link>
<router-link to="/mypage/playground" class="link">ํ๋ ์ด๊ทธ๋ผ์ด๋</router-link>
<router-link to="/help/faq/" class="link">ํ์ต์ง์์ผํฐ</router-link>
<router-link to="/my_study" class="link">๋ด ๊ฐ์์ค</router-link>
<router-link to="/mypage" class="link">MY</router-link>
</div>
<div class="auth">
<router-link to="/login" class="login">๋ก๊ทธ์ธ</router-link>
<router-link to="/register" class="join">ํ์๊ฐ์
</router-link>
</div>
</div>
</div>
</div>
<div class="gnb-area">
<div class="gnb">
<h1 class="logo">
<router-link to="/">
<img src="https://img.megagong.net/s/gong/logo_nextgong.png" alt="๋ฅ์คํธ๊ณต๋ฌด์" />
</router-link>
</h1>
<nav class="nav">
<ul>
<li><router-link to="/pass">๋ฅ์คํธํจ์ค</router-link></li>
<li><router-link to="/vod/vod_chr_list">์๊ฐ์ ์ฒญ</router-link></li>
<li><router-link to="/teacher">์ ์๋</router-link></li>
<li><router-link to="/fullservice">ํฉ๊ฒฉ์์ธก ํ์๋น์ค</router-link></li>
<li><router-link to="/lab">์ํ์ ๋ณด</router-link></li>
<li><router-link to="/event">์ด๋ฒคํธ</router-link></li>
<li><router-link to="/book">๊ต์ฌ</router-link></li>
</ul>
</nav>
</div>
</div>
</header>
</template>
<script>
export default {
name: "AppHeader",
};
</script>
<style lang="scss" scoped>
.header {
border-bottom: 1px solid #ddd;
background-color: white;
.top-inner {
width: 1200px;
margin: 0 auto;
display: flex;
justify-content: space-between;
}
.hcode_wrap {
display: flex;
gap: 10px;
a.on {
color: #0055ff;
}
}
.login_wrap {
display: flex;
}
.top-bar {
display: flex;
justify-content: space-between;
font-size: 12px;
padding: 10px 20px;
background: #f8f8f8;
color: #555;
.util {
display: flex;
gap: 12px;
.day {
color: #0055ff;
font-weight: bold;
}
.link {
color: #333;
text-decoration: none;
}
}
.auth {
display: flex;
gap: 12px;
a {
color: #333;
text-decoration: none;
}
}
}
.gnb-area {
max-width: 1200px;
margin: 0 auto;
.gnb {
display: flex;
justify-content: space-between;
align-items: center;
padding: 30px 0px;
.logo img {
height: 28px;
}
.nav ul {
display: flex;
gap: 24px;
li a {
text-decoration: none;
color: #111;
font-weight: 500;
font-size: 15px;
&:hover {
color: #0055ff;
}
}
}
}
}
}
</style>
๐งฉ src/components/Footer.vue
<template>
<footer class="footer">
<div class="footer-inner">
<ul class="footer-links">
<li><a href="#">ํ์ฌ์๊ฐ</a></li>
<li><a href="#">์ด์ฉ์ฝ๊ด</a></li>
<li><a href="#">๊ฐ์ธ์ ๋ณด์ฒ๋ฆฌ๋ฐฉ์นจ</a></li>
<li><a href="#">๊ณ ๊ฐ์ผํฐ</a></li>
</ul>
<div class="footer-info">
<p>
์์ธํน๋ณ์ ๊ตฌ๋ก๊ตฌ ๊ฒฝ์ธ๋ก 662, ํ์๋ 31์ธต(์ ๋๋ฆผ๋, ๋ํ๋ธ์ํฐ) ใ๋ฅ์คํธ์คํฐ๋ ๋ํ์ด์ฌ
์คํํฌ ๊ฐ์ธ์ ๋ณด๋ณดํธ์ฑ
์์ ์คํํฌ (keeper@megagong.net)
</p>
<p>
๋ฉ๊ฐ์คํฐ๋๊ต์ก ์๊ฒฉํ์๊ต์ก์์ค(์ 434ํธ) (์ฃผ)๋ฅ์คํธ์คํฐ๋ ์ฌ์
์๋ฑ๋ก๋ฒํธ : 561-81-03379
ํต์ ํ๋งค์
์ ๊ณ ๋ฒํธ : ์ 2025-์์ธ๊ตฌ๋ก-1079ํธ
</p>
<p>์ ๊ณ ๊ธฐ๊ด๋ช
: ์์ธ์ ๊ฐ๋จ๊ตฌ ํธ์คํ
์ ๊ณต์ : (์ฃผ)์ผ์ดํฐ</p>
<p class="copyright">Copyright ยฉ nextstudy.co.,Ltd. All rights reserved.</p>
</div>
</div>
</footer>
</template>
<script>
export default {
name: "AppFooter",
};
</script>
<style scoped lang="scss">
.footer {
background-color: #f5f6f7;
border-top: 1px solid #ddd;
font-size: 13px;
color: #666;
.footer-inner {
max-width: 1200px;
margin: 0 auto;
padding: 24px 0;
}
.footer-links {
display: flex;
flex-wrap: wrap;
gap: 12px;
margin-bottom: 12px;
li {
list-style: none;
a {
color: #444;
text-decoration: none;
&:hover {
text-decoration: underline;
}
}
}
}
.footer-info {
line-height: 1.6;
}
.copyright {
margin-top: 8px;
font-size: 12px;
color: #999;
}
}
</style>
๐งฉ src/components/LeftQuickMenu.vue
<template>
<div class="left-quickmenu">
<div>[ ์ข์ธก ์ฌ์ด๋ ๊ณ ์ ๋ฉ๋ด ]</div>
</div>
</template>
๐งฉ src/components/RightQuickMenu.vue
<template>
<div class="right-quickmenu">
<div>[ ์ฐ์ธก ์ฌ์ด๋ ๊ณ ์ ๋ฉ๋ด ]</div>
</div>
</template>
๐งฉ src/components/StickyPanel.vue
<template>
<div class="sticky-panel">
<div>[ ์ฐ์ธก ์ฝํ
์ธ ๊ณ ์ ]</div>
</div>
</template>
๐งฉ src/components/MainTabs.vue
<template>
<div class="main-tabs">
<div class="slide-banner">[ ํญ + ์ฌ๋ผ์ด๋ ์น์
]</div>
</div>
</template>
๐งฉ src/App.vue
<template>
<div>
<MainHeader />
<router-view />
<MainFooter />
</div>
</template>
<script>
import MainHeader from "@/components/Header.vue";
import MainFooter from "@/components/Footer.vue";
export default {
components: {
MainHeader,
MainFooter,
},
};
</script>
์ ์์ ์ผ๋ก ์ ๋ฐ๋ผ์๋ค๋ฉด ์์ ๊ฐ์ ํ๋ฉด์ ํ์ธํ์ค ์ ์์ต๋๋ค.
์ ์ฅ์
GitHub - heroyooi/vue2-megagong at ch2
๐ ๊ณผ์
- ์๋จ ๋ฉ์ธ ์ฌ๋ผ์ด๋ (
MainVisual.vue
) ์์ฑ- Slick or Swiper ๋ก ๊ตฌํ
๐ฌ ๋๊ธ
โป ๋ก๊ทธ์ธ ํ ๋๊ธ์ ์์ฑํ ์ ์์ต๋๋ค.