본문 바로가기
Frontend/Vue 2

[vue]컴포넌트 자세히 알아보기

by SOLYI 2023. 1. 10.

1. 섹션 소개

  • 컴포넌트 등록 및 스타일에 대해 Component Registration & Styling
  • 컴포넌트를 스타일링 하는 방법과 특정 스타일이 특정 컴포넌트에만 영향을 미치도록 하는 방법도 알아본다
  • 슬롯과 동적 컴포넌트 Slots & Dynamic Components
  • 컴포넌트 이름과 프로젝트 폴더 구조 Naming & Folder structure

 

2. 전역 컴포넌트Global Components와 지역 컴포넌트Local Components

main.js에서 app.component('the-header', TheHeader); 처럼 설정하는건 vue앱의 전역에서 사용할 수 있는 컴포넌트다. 하지만 컴포넌트를 등록하는 방법 중에서 가장 좋은 방법은 아니다.

한가지 잠재적 단점이 있다. 모든 컴포넌트에는 당연히 코드가 들어있는데 template 코드도 있고 script 코드도 있다. 애플리케이션이 커질수록 이 코드도 커지게 된다. 컴포넌트가 많을수록 코드 패키지도 더 많아진다.

main.js에 모든 컴포넌트를 전역으로 등록하게 되면 애플리케이션이 처음 로드 될때 결국 모든 컴포넌트를 다운로드해야한다.

사용하려는 컴포넌트에서 지역적local으로 등록할 수 있다.

// App.vue
<template>
	위 생략
	// SelfClosing은 대시가 있으면 사용할 수 없다.
	// 아래 두가지 방법 중 택 1
	<the-header></the-header>
	<TheHeader />  
	아래 생략
</template>

<script>
import TheHeader from './components/TheHeader.vue'
export default{
	**components: {
		// 아래 세가지 방식으로 작성할 수 있다.
		'the-header': TheHeader
		TheHeader: TheHeader
		TheHeader
	}**
}
</script>

다양한 곳에서 사용되는 컴포넌트는 전역 컴포넌트로, 특정 페이지에서만 사용되는 컴포넌트는 지역 컴포넌트로 등록한다.

3. 범위가 지정된Scoped 스타일

어플리케이션 전체에 영향을 끼치는 style의 경우 일반적으로 App.vue의 style태그에 정의된다.

하지만 개별 컴포넌트에 적용할 스타일이 있는 경우에는 scope를 정한다.

<style scoped>

다른 부모, 형제 컴포넌트에는 영향을 끼치지 않고 오직 작성된 컴포넌트에만 영향을 끼친다.

4. 슬롯Slots 소개

vue 기능을 사용할 수도 있는 HTML 컨텐츠를 외부 컴포넌트로부터 수진할 수있게 해준다.

기본적으로 props와 같지만, props는 컴포넌트가 필요로 하는 데이터에 사용되고

슬롯은 컴포넌트에 필요한 템플릿 코드의 HTML 코드에 사용된다.

5. 이름이 있는 슬롯 Named slots

슬롯에 name속성을 사용해서 슬롯에 이름을 추가 할 수 있다.

<slot name=”header”></slot>

이름이 없는 슬롯을 하나 남겨두면 그것이 기본 슬롯이 된다.

// BaseCard.vue
<template>
  <div>
    <header>
      **<slot name="header"></slot>**
    </header>
    <slot></slot>
  </div>
</template>

// UserInfo.vue
<template>
  <section>
    <base-card>
      **<template v-slot:header>**
        <h3>{{ fullName }}</h3>
        <base-badge :type="role" :caption="role.toUpperCase()"></base-badge>
      **</template>**
      <p>{{ infoText }}</p>
    </base-card>
  </section>
</template>

6. 슬롯 스타일 및 컴파일

7. 슬롯에 대한 추가 정보

v-slot의 약어는 #

v-slot:header == #header

8. 범위가 지정된(Scoped) 슬롯

9. 동적 컴포넌트

**<component :is="selectdComponent"></component>**

<script>
 ...
  data() {
		return {
			**selectedComponent**: 'active-goals'
		}
  },
	methods: {
		setSelectedComponent(cmp){
			this.**selectedComponents** = cmp;
		}
	}

</script>

10. 동적 컴포넌트를 활성 상태로 유지하기

118의 코드에서 <active-goals> 라는 컴포넌트 안에 input 태그가 있을때, 컴포넌트를 변경하게 되면 input 태그가 destroy 후 다시 create 되면서 input 에 있던 값이 삭제 되게 된다.

이때 사용하는 것이 <keep-alive>

**<keep-alive>**
	<component :is="selectedComponent"></component>
**</keep-alive>**

keep-alive 는 컴포넌트를 완전히 제거하지 않고 내부에서 캐시로 저장하도록 vue 에 알려준다.

그러면 컴포넌트를 이동하더라도 input에 있는 값이 그대로 유지되게 된다.

11. 이론 적용하기 & 한가지 문제점 (커스텀 오버레이)

javascript 의 alert(’경고내용’)을 쓰는건 사이트와 어울리지 않을수 있기 때문에 오버레이 다이어로그를 만드는게 더 좋다.

// ErrorAlert.vue
<template>
	**<dialog open>
		<slot></slot>  // 아래 파일의 h2, p 를 여기에 표시
	</dialog>**
</template>

<style scoped>
dialog {
	margin: 0;
	position: fixed;
	top: 20vh;
	left: 30%;
	width: 40%;
	background-color: white;
	box-shadow: 0 2px 8px rgba(0,0,0,0.26);
	padding: 1rem;
}
</style>

위 dialog를 보여줄 component 에는 다음과 같이 입력한다.

<template>
	<div>
		<input type="text" ref="goal" />
		<button @click="setGoal">Set Goal</button>
		<error-alert v-if="inputIsInvalid">
			<h2> input is invalid!</h2>
			<p>Please enter at least a few characters...</p>
			<button @click="confirmError">Okay</button>
		</error-alert>
	</div>
</template>

<script>
import errorAlert from './ErrorAlert.vue'
export default{
	components: {
		ErrorAlert
	}
	data() {
		return {
			inputIsInvalid: false
		}
	},
	methods: {
		setGoal(){
			const enteredValue = this.$refs.goal.value;
			if (enteredValue === '') {
				// alert('Input must not be empty.')
				this.inputIsInvalid = true
			}
		},
		confirmError(){
			this.inputIsInvalid = false;	
		}
	}
}
</script>

12. 텔레포트를 활용하여 요소 이동시키기

120 처럼 코드를 작성하면 정상적으로 화면에 보이는듯 하지만 개발자도구-요소 에서 확인해보면 html 태그들의 하위에 위치하기 때문에 시맨틱 적으로 좋은 코드라고 할 수 없다.

그래서 <div class=app> 바로 하위에 위치 시킬 수 있는 방법이 있는데 teleport 이다.

// 위와 동일한 코드에 teleport 를 추가해준다.
<template>
	<div>
		<input type="text" ref="goal" />
		<button @click="setGoal">Set Goal</button>
		**<teleport to="body">  // body 에서 직접 렌더링 하도록 요구. html 구조에 깊게 중첩되지 않도록.**
			<error-alert v-if="inputIsInvalid">
				<h2> input is invalid!</h2>
				<p>Please enter at least a few characters...</p>
				<button @click="confirmError">Okay</button>
			</error-alert>
			**</teleport>**
	</div>
</template>

위와같이 작성하면 </body> 의 바로 위에 해당 내용이 추가 되어 시맨틱 측면에서 더 나은 코드를 작성할 수 있다.

13. 프래그먼트Fragment 활용하기

vue2에서는 template 태그 내에 루트 레벨의 요소는 하나만 있어야 했는데 vue3에서는 여러개 일 수 있다.

<template> 안에 <div>를 쓰고 그안에 여러 요소를 써야하는 vue2 와 달리

vue3에서는 <template> 안에 h2, input, button 등을 바로 쓸 수 있다.

이것들을 fragment 라고 한다.

14. Vue 스타일 가이드

Style Guide - Vue.js

Style Guide | Vue.js

https://v2.vuejs.org/v2/style-guide/?redirect=true#Base-component-names-strongly-recommended

위의 스타일 가이드 링크에서 확인해보면

여러번 쓰이는 컴포넌트의 경우 BaseButton.vue BaseTable.vue BaseIcon.vue 와 같이 Base를 붙이거나 AppButton.vue AppTable.vue 과 같이 App을 붙이거나 VButton.vue 와 같이 V를 붙이는 방식을 추천한다.

한번만 쓰이는 컴포넌트의 경우 TheHeader.vue TheSideBar.vue와 같이 The 를 붙인다.

15. 다른 폴더 구조로 이동하기

지금까지는 components 폴더 안에 모든 컴포넌트를 두었지만 프로젝트 규모가 커지면 이와 같이 만들기보다 폴더를 만들고 그 하위에 Vue파일을 두는것이 좋다.

예를 들어 Base 라는 폴더 내에 BaseCard.vue BaseButton.vue 등의 파일을 두는것이 좋다.

layout 폴더 내에는 header, footer 등을 둔다.

기능에 따라서 정리되어야 하는 여러 컴포넌트들은 예를들어 cart, checkout, products 등의 폴더를 만들어 관련 컴포넌트를 넣어둘 수 있다.

16. 섹션 요약

  • 컴포넌트 등록 및 스타일 : 전역등록, 지역등록, scoped스타일
  • Slots 외부에서 컴포넌트로 삽입될수 있는 동적 컴포넌트. 여러 슬롯은 이름을 지정해야하고, 슬롯 한개의 경우 이름 없이 사용할 수 있다.
  • 동적 컴포넌트 : 내장된 component라는 컴포넌트를 활용하는 기능. 다른 컴포넌트와 동적으로 교환하는데에 이 기능이 사용된다. keep-alive를 사용하여 컴포넌트를 캐싱할수 있다.
  • 텔레포트와 공식 스타일 가이드
반응형