관리자 페이지

admin 페이지 제작 튜토리얼

관리자 메인 페이지

블로그 글을 작성하거나, 작성된 글들을 편집할 수 있는 관리자 권한의 페이지를 제작합니다.client/pages/admin/index.vue 파일을 만든 후 템플릿, 스크립트, 스타일 코드를 작성합니다.

client/pages/admin/index.vue
<template lang="pug">
.page-admin.container
section.create-post
h2.page-title 포스트 생성
p 새로운 글을 작성합니다.
button.button(type="button") 생성
section.posts
h2.page-title 포스트 리스트
p 작성된 글들 입니다.
post-list
</template>
<script>
import PostList from '@/components/Posts/PostList'
export default {
components: { PostList }
}
</script>
<style lang="sass" scoped>
@import "~assets/styles/config"
.page-admin
padding: 20px
.create-post
border-bottom: 1px solid rgba(#000, 0.2)
padding-bottom: 30px
.page-title
margin-bottom: 0
font-family: Changa, Sans-Serif
letter-spacing: -0.03em
.posts
margin-top: 30px
p
margin-top: 0
color: rgba(#000, 0.5)
font-size: 13px
letter-spacing: -0.06em
.button
cursor: pointer
border: none
border-radius: 4px
padding: 0.6em 1.2em
background: rgba(darken($point-color, 40%), 0.7)
color: #fff
font-weight: bold
transition: all 0.4s ease-out
&:hover,
&:focus
background: darken($point-color, 20%)
</style>

작성된 관리자 페이지에 접속하면 아래 이미지처럼 화면에 그려집니다.

UI 버튼 컴포넌트

앞서 관리자 페이지에서 만든 버튼 스타일을 UI 버튼 컴포넌트로 변경해봅니다. 컴포넌트로 만들어 다른 페이지에서도 UI 버튼 컴포넌트를 재사용 할 수 있습니다. client/components/UI/UiButton.vue 파일을 만들어 코드를 작성합니다.

$attrs, $listeners는 Vue.js를 사용해 컴포넌트를 만들 때 자주 사용됩니다. 각 값은 부모 컴포넌트의 속성, 이벤트 바인딩 값이 자식 컴포넌트에 전달될 수 있도록 만들어 줍니다.

client/components/UI/UiButton.vue
<template lang="pug">
button(
class="ui-button"
:class="styles"
v-bind="$attrs"
v-on="$listeners"
)
slot
</template>
<script>
export default {
props: {
styles: { type: String, default: '' }
}
}
</script>
<style lang="sass" scoped>
@import "~assets/styles/config"
// 컬러 변수 기본 값
$point-color: #0826c0 !default
$cancel-color: #d43c6d !default
.ui-button
cursor: pointer
border: none
border-radius: 4px
padding: 0.6em 1.2em
background: rgba(darken($point-color, 5%), 0.7)
color: #fff
font-weight: bold
transition: all 0.4s ease-out
&:hover,
&:focus
background: darken($point-color, 20%)
// 클래스 확장
&.inverted
background: #efefef
border: 1px solid transparent
color: $point-color
&:hover,
&:focus
background: #dedede
&.cancel
background: rgba(darken($cancel-color, 10%), 0.7)
color: #fff
&:hover,
&:focus
background: $cancel-color
</style>

UI 인풋 컴포넌트

글을 작성하는 폼을 구성할 때 인풋 컴포넌트가 필요하므로 UI 인풋 컴포넌트를 추가합니다. client/components/UI/UiInput.vue 파일을 만든 후 코드를 작성합니다.

client/components/UI/UiInput.vue
<template lang="pug">
.ui-input-control(role="group")
label(:for="uniqueId", :style="{display: computedDisplay}")
slot
input(
v-if="controlType === 'input'",
:id="uniqueId",
:aria-label="computedLabel"
:placeholder="computedLabel"
:value="value",
v-bind="$attrs",
@input="$emit('input', $event.target.value)"
)
textarea(
v-if="controlType === 'textarea'",
:id="uniqueId",
v-bind="$attrs",
:value="value",
@input="$emit('input', $event.target.value)",
rows="5"
)
</template>
<script>
export default {
props: {
uniqueId: { type: String, required: true },
controlType: { type: String, default: 'input' },
labelHidden: { type: Boolean, default: null },
value: { type: String, default: '' }
},
data() {
return {
label: null
}
},
computed: {
computedDisplay() {
return this.labelHidden ? 'none' : 'block'
},
computedLabel() {
return this.labelHidden ? this.label : null
}
},
mounted() {
// 사용자가 전달한 slot 콘텐츠
this.label = this.$slots.default[0].text
}
}
</script>
<style lang="sass" scoped>
@import "~assets/styles/config"
.ui-input-control
margin: 10px 0
label
display: block
font-weight: bold
margin-top: 20px
margin-bottom: 10px
input,
textarea
display: block
width: 100%
border: 1px solid $point-color
border-radius: 4px
padding: 0.4em
font: inherit
transition: background-color 0.4s ease
&:focus
background-color: rgba(lighten($point-color, 20%), 0.1)
outline: 1px solid $point-color
textarea
padding: 0.95em
</style>

UI 컴포넌트 활용

client/pages/admin/index.vue 파일을 열어 UiButton 컴포넌트를 불러와 등록한 후, 템플릿에 추가합니다. 그리고 기존에 작성했던 .button 스타일 코드는 제거합니다.

client/pages/admin/index.vue
<template lang="pug">
ui-button(type="button") 생성
</template>
<script>
// UiButton 컴포넌트 불러오기
import UiButton from '@/components/UI/UiButton'
export default {
// UiButton 컴포넌트 등록
components: { PostList, UiButton }
}
</script>

포스트 생성 페이지

client/pages/admin/create/index.vue 파일을 생성한 후, 글을 입력하는 폼을 작성합니다.

client/pages/admin/create/index.vue
<template lang="pug">
.page-admin-create.container
section.create-post-form
h2.page-title 포스트 생성
p 새로운 글을 작성합니다.
form(@submit.prevent="onSave")
ui-input(uniqueId="author", v-model="post.author") 작성자
ui-input(uniqueId="title", v-model="post.title") 제목
ui-input(uniqueId="thumbnail", v-model="post.thumbnail") 썸네일 이미지 링크
ui-input(controlType="textarea", uniqueId="content", v-model="post.content") 콘텐츠
ui-button 저장
ui-button(
type="button",
style="margin-left: 10px",
styles="cancel",
@click="onCancel"
) 취소
</template>
<script>
import UiButton from '@/components/UI/UiButton'
import UiInput from '@/components/UI/UiInput'
export default {
components: {
UiButton,
UiInput
},
data() {
return {
post: {
author: '',
title: '',
thumbnail: '',
content: ''
}
}
},
methods: {
onSave() {
// 글 저장 (비동기 통신 후 백엔드 DB에 저장)
// 추후 구현
console.log(this.post)
},
onCancel() {
this.$router.push('/admin')
}
}
}
</script>
<style lang="sass" scoped>
@import "~assets/styles/config"
.page-title
margin-bottom: 0
font-family: Changa, Sans-Serif
letter-spacing: -0.03em
p
margin-top: 0
color: rgba(#000, 0.5)
font-size: 13px
letter-spacing: -0.06em
</style>

글 입력 페이지를 만들었으니, 관리자 메인 페이지에 있는 생성 버튼을 누르면 연결되도록 해야 합니다. $router.push 메서드를 사용해 '/admin/create' 라우트를 설정합니다.

client/pages/admin/index.vue
<template lang="pug">
.page-admin.container
section.create-post
h2.page-title 포스트 생성
p 새로운 글을 작성합니다.
ui-button(
type="button",
@click="$router.push('/admin/create')"
) 생성
section.posts
h2.page-title 포스트 리스트
p 작성된 글들 입니다.
post-list
</template>

관리자 메인 페이지 생성 버튼을 누르면 포스트 생성 페이지로 잘 연결되고, 아래 이미지처럼 화면에 표시됩니다. 내용을 입력한 후, 저장 버튼을 누르면 개발도구 콘솔 패널에 사용자가 입력한 post 정보를 확인할 수 있습니다.

완성 코드 참고

완료된 코드는 아래 링크를 통해 ZIP 파일을 다운로드 받아 확인할 수 있습니다.