[Vue] HOC (하이 오더 컴포넌트) [ Index.vue 공통화 - 함수형 컴포넌트 ]

suhanLee·2022년 7월 6일
0

vue-basic

목록 보기
21/29

기존의 문제점 : layout 구조에서
subjects : category, product, serach, wish ... 등등..

Appbar, View, Footer를 한 곳에 정의하려면 Index.vue가 필요했음 ( 사소한 차이밖에 없는 파일이 쓸데없이 늘어남 -> 어느화면은 AppBar가 없고 어느화면은 Footer가 없고.. )

기존 라우터 구성

기존 src/layouts/[subject_name]/Index.vue

( 물론.. Index.vue파일을 하나만 만들고 그 쪽만 바라보게 한 뒤
내부 로직에서 v-if나 v-show로 라우팅객체($route) 정보를 가지고 분기 쳐도 됨.. 대신 지저분해짐)

그래서 Index.vue를 Vue.component로 공통 함수로 만들거다.

AppBar.vue ( 헤더 영역 )

src/layouts/appbars/CustomAppBar.vue

<template>
	<v-app-bar app color="primary" dark>
		<span @click="$emit('left')"></span>
		<v-spacer />
		<span @click="$emit('center')"> 쎈터 </span>
		<v-spacer />
		<span @click="$emit('right')"></span>
	</v-app-bar>
</template>

<script>
	export default {};
</script>

<style></style>

View.vue ( 뷰 영역 )

src/layouts/CustomView.vue

<template>
	<v-main>
		<router-view />
	</v-main>
</template>

<script>
	export default {};
</script>

<style></style>

Footer.vue ( 푸터 영역 )

src/layouts/CustomFooter.vue

<template>
	<v-footer class="pa-0" app> 푸터입니당 </v-footer>
</template>

<script>
	export default {};
</script>

<style></style>

App.vue

src/App.vue

<template>
	<v-app>
		<router-view />
	</v-app>
</template>

<script>
	export default {
		name: 'App',
	};
</script>

Index.vue (전체 레이아웃 영역)

각 subject별 Index.vue파일을 만들지 않기 위해 공통화

/src/utils/utils.js - createComponent

import Vue from 'vue';
export default function createComponent(...childs) {
	const DefaultComponent = Vue.component('TempView', {
		template: '<div></div>',
	});
	return Vue.component('Index', {
		template: `
    <div>
      <CustomAppbar @left="clickLeft" @center="clickCenter" @right="clickRight"></CustomAppbar>
      <CustomView></CustomView>
      <CustomFooter></CustomFooter>
    </div>
    `,
		data: function () {
			return {
				message: '메시지테스트',
			};
		},
		components: {
			CustomAppbar: childs[0] ?? DefaultComponent,
			CustomView: childs[1] ?? DefaultComponent,
			CustomFooter: childs[2] ?? DefaultComponent,
		},
		computed: {},
		mounted() {
			console.log('zz');
		},
		props: {
			id: Number,
			name: String,
			hp: Number,
		},
		methods: {
			// 버튼 클릭 이벤트 핸들러에서 $emit을 호출해서 attack 이벤트 실행하기
			clickLeft() {
				console.log('left');
			},
			clickCenter() {
				console.log('center');
			},
			clickRight() {
				console.log('right');
			},
		},
		// functional 컴포넌트 시에는...
		//functional: true,
		// render: function (createElement, context) {
		// 	debugger;
		// 	return createElement('div', context.props.message);
		// },
	});
}

router

src/router/index.js

...(생략)
import createComponent from '@/utils/utils.js';
const routes = [
  	...(생략)
	{
		path: '/parent',
		name: 'Parent',
		component: createComponent(
			() => import('@/layouts/appbars/CustomAppBar1.vue'),
			() => import('@/layouts/CustomView1.vue'),
			//() => import('@/layouts/CustomFooter1.vue'),
		),
		children: [
			{
				path: 'children',
				name: 'ChildrenPage',
				component: () => import('@/views/ChildrenPage.vue'),
			},
		],
	},
    ...(생략)
]
const router = new VueRouter({
	mode: 'history',
	base: process.env.BASE_URL,
	routes,
});

export default router;

view

src/views/ChidrenPage.vue

<template>
	<div>view 페이지 영역입니다.</div>
</template>

<script>
	export default {};
</script>

<style></style>

vue.config.js

template : '' -> 사용을 위한 런타임 컴파일러 : true

module.exports = {
  	publicPath: '/', //(필수 설정)
	runtimeCompiler: true,
};

요약

파일 구조가 왼쪽에서 오른쪽으로 변경 됨


기타 참고 :
https://rintiantta.github.io/jpub-vue/guide/chapter5.html#sync%EB%A1%9C-%EC%96%91%EB%B0%A9%ED%96%A5-%EB%8D%B0%EC%9D%B4%ED%84%B0-%EB%B0%94%EC%9D%B8%EB%94%A9%ED%95%98%EA%B8%B0

0개의 댓글