환경
- Node v10.16.0
- Vuetify2
Vuetify와 Vuex를 사용하여 2뎁스까지 지원하는 메뉴 체계를 작성해 보았습니다.
화면구성
Menus.vue : 메뉴 출력 및 동작 컴포넌트
PageTitle.vue : 페이지 타이틀 아이콘/이름 출력 컴포넌트
Index.vue : 라우터로 이동될 페이지
메뉴 이동에따라 화면을 전환하고 PageTItle내용을 수정해 주겠습니다.
Index.vue (메뉴설정) 부분에는 메뉴 색상 및 메뉴 추가, 삭제 기능이 있습니다.
store/state/color.js
const colorState = {
colors: {
menu_background_color: '#263238',
menu_selected_color: 'red',
}
}
export default colorState;
메뉴의 배경 색상 (menu_background_color)과, 메뉴 선택시 색상(menu_selected_color)을 담을 변수
menu_background_color 는 RGB 색상코드, menu_selected_color 는 vuetilfy의 Material color 체계를 채택하였습니다.
https://vuetifyjs.com/en/styles/colors/#material-colors
store/state/menus.js
const menuState = {
menus: [
{
id:1,
icon: "loop",
title: "메뉴 설정",
target: "Index",
},
{
id:2,
icon: "android",
title: "페이지2",
target: "Page2",
model: false,
childrens: [
{
id:21,
icon: "assignment_ind",
title: "페이지2_1",
target: "Page2_1",
},
{
id:22,
icon: "people_alt",
title: "페이지2_2",
target: "Page2_2",
}
]
},
{
id:3,
icon: "trending_up",
title: "페이지3",
target: "Page3",
},
]
}
export default menuState;
전체적인 메뉴의 기본 틀이될 데이터형식은 아래와 같습니다.
{
id: int, //id 값은 고유번호로 설정
icon: String, //Material icon 형식의 이름
title: String, //메뉴의 이름
target: String, //메뉴 클릭시 이동될 roturer의 이름
childrens : [], //2뎁스의 메뉴 사용시 설정
}
router/index.js
import Vue from "vue";
import VueRouter from "vue-router";
import Menus from "../components/Menus.vue";
import Index from "../view/Index.vue";
import Page2_1 from "../view/Page2_1.vue";
Vue.use(VueRouter);
const routes = [
{
path: '/',
name: 'Index',
components: {
menu: Menus,
content: Index,
},
},
{
path: '/Page2_1',
name: 'Page2_1',
components: {
menu: Menus,
content: Page2_1,
},
},
{
path: '/Page2_2',
name: 'Page2_2',
components: {
menu: Menus,
content: { template: `
<div style="width: 100%;
height: 100%;
background-color: green;">test</div>
`},
},
},
{
path: '/Page3',
name: 'Page3',
components: {
menu: Menus,
content: { template: `
<div style="width: 100%;
height: 100%;
background-color: gray;">test</div>
`},
},
},
]
export const router = new VueRouter({
routes
});
store/state/menus.js의 target 과 router/index.js의 name의 이름을 동일하게 맞춰줍니다.
Menus.vue
<template>
<div>
<v-navigation-drawer
id="app-drawer"
v-model="drawer"
app
dark
:color="colors.menu_background_color"
floating
persistent
mobile-break-point="960"
width="280"
>
<div>
<v-layout
class="fill-height"
tag="v-list"
column
>
<v-list>
<v-list-item @click="movePage('');">
<v-toolbar-title><v-icon class="mr-2">home</v-icon>JoBlog</v-toolbar-title>
</v-list-item>
<hr class="mt-2 mb-2">
<v-list-item-group active-class="white--text">
<template v-for="menu in menus">
<template v-if="menu.childrens"> <!-- 자식 메뉴가 있는경우 -->
<v-list-group
:prepend-icon="menu.icon"
:key="menu.id"
>
<template v-slot:activator>
<v-list-item-title>{{menu.title}}</v-list-item-title>
</template>
<template v-for="children in menu.childrens">
<v-list-item
@click="movePage(children.target);"
:key="children.id"
class="ml-2"
:active-class="`${colors.menu_selected_color} accent-4 white--text`"
>
<v-list-item-icon :active-class="`${colors.menu_selected_color} accent-4`">
<v-icon>{{children.icon}}</v-icon>
</v-list-item-icon>
<v-list-item-title>
{{children.title}}
</v-list-item-title>
</v-list-item>
</template>
</v-list-group>
</template>
<template v-else> <!-- 단일 메뉴일 경우 -->
<v-list-item
@click="movePage(menu.target);"
:key="menu.id"
:active-class="`${colors.menu_selected_color} accent-4 white--text`"
>
<v-list-item-icon>
<v-icon>{{menu.icon}}</v-icon>
</v-list-item-icon>
<v-list-item-title>{{menu.title}}</v-list-item-title>
</v-list-item>
</template>
</template>
</v-list-item-group>
</v-list>
</v-layout>
</div>
</v-navigation-drawer>
</div>
</template>
<script>
import { mapState } from "vuex";
import _ from "lodash";
export default {
components: {
},
data: () => ({
drawer: null,
color: 'success',
responsive: false,
}),
computed: _.extend(
mapState(["menus", "colors"]),
),
mounted(){
this.onResponsiveInverted()
window.addEventListener('resize', this.onResponsiveInverted)
},
methods: {
movePage(target){
this.$router.push({ name: target });
},
onResponsiveInverted () {
if (window.innerWidth < 1000) {
this.responsive = true
} else {
this.responsive = false
}
},
},
}
</script>
<style lang="scss">
#app-drawer {
.v-list__tile {
border-radius: 4px;
&--buy {
margin-top: auto;
margin-bottom: 17px;
}
}
}
</style>
참고 자료
https://vuetifyjs.com/en/components/list-item-groups/#list-item-groups
https://demos.creative-tim.com/vuetify-material-dashboard/#/
전체 소스
https://github.com/Jo-App/vuetilfy_menu
'개발이야기 > Vuetify' 카테고리의 다른 글
[Vuetify] 데이터 테이블 헤더 show/hide (2) | 2021.06.12 |
---|---|
[Vuetify] 자주 사용하는 색상 네이밍 지정하기 (0) | 2020.10.13 |
[Vuetify] DatePicker + TimePicker (0) | 2020.07.13 |
[Vuetify] Data table 무한뎁스 처리 (0) | 2020.02.13 |
[Vuetify] 다중 업로드 모달창 만들기 (0) | 2020.01.18 |