단일 컴포넌트
# 전역수준 컴포넌트 문제점
컴포넌트 관리가 어렵고 재사용성이 낮아진다.
- 빌드 단계가 없으므로 ES2015, TypeScript와 같은 최신 버전 자바스크립트 문법을 사용할 수 없다. (ES 2015 전 문법 작성만 가능)
- CSS를 지원하지 않는다. 컴포넌트들은 고유한 스타일 정보를 포함하는 경우가 많으나, 전역 컴포넌트에서는 CSS 스타일을 빌드하고 모듈화하는 기능을 제공하지 않는다.
- css를 <link>방식이 아니라 모듈 처럼 참조(import)할 수 없다. → 모듈 처럼 사용할 경우 빌드 거치면 자체적으로 link 태그를 만든다.
- 컴포넌트들의 템플릿이 작성될 때, HTML 파일 안에 여러 개의 <template/> 태그가 작성되어 식별하기 어렵다. 또한 템플릿마다 고유한 ID를 부여하고 컴포넌트들도 고유한 이름을 지정해야 한다.
# 단일 파일 컴포넌트
확장자가 .vue인 파일을 컴포넌트 단위로 생성한다. 크게 3가지로 나누어짐
- <template>
- <script>
- <style> // 클래스 기반으로 작성해야 컴포넌트 기반 (모듈) 스타일 적용이 가능함.
사용할 컴포넌트는 등록해줘야 사용이 가능하다.
등록 방법은 전역 등록과 지역 등록이 있다.
dreamcoding.tistory.com/8?category=952284 참고
# 전역 컴포넌트와 차이점
- <template>에 id 특성을 부여하지 않는다.
- <script>영역에서는 Vue컴포넌트의 template을 지정하지 않는다.
- Vue.component로 이름과 template 속성을 지정하지 않는다.
- name 속성은 지정할 수 있다.
- name은 컴포넌트 파일명과 동일하게 작성하는 것이 좋음.
- import한 모듈명이 아닌 설정한 name으로 template 가져다 쓸 수 있음 → 모듈명과 정확한 상관관계 확인 필요
- ex) script: { components: ListComponent }
- ex) html: <list-component></list-component>
- 반드시 적어야 되는건 아니지만 name 옵션을 설정해야 vue devtools에서 디버깅할 때 이름이 나오므로 지정하는 것이 좋음.
- 하나의 단어일 경우 별도 name 작성은 필요없다.
- 반드시 객체를 export해야 한다.
- 컴포넌트에서 사용할 스타일은 <style> 내부에서 작성한다.
단일 컴포넌트
<template>
<div id='app'> .. </div>
</template>
<script>
export default {
name: 'app',
data() {
return {
msg: 'test'
}
}
}
</script>
<style>
#app { .. }
</style>
단일 컴포넌트 사용
import Vue from 'vue'
import TodoList from './components/TodoList'
Vue.config.productionTip = false
/* eslint-disable no-new */
new Vue({
el: '#app',
components: { TodoList }, // 지역 등록
template: '<TodoList/>'
})
컴포넌트 스타일
특정 컴포넌트만의 스타일 지정할 수 있으며, 다음과 같은 방법이 있다.
- 범위 CSS (Scoped CSS)
- CSS 모듈(CSS Module)
# 범위 CSS (Scoped CSS)
<style scoped>로 설정 특성 선택자(attribute selector)를 사용하기 때문에 브라우저에서 스타일을 적용하는 속도가 느리다. 그렇기 때문에 반드시 속도가 빠른 ID 선택자, 클래스 선택자, 태그명 선택자로 요소를 선택해 스타일을 적용하도록 해야한다.
- traverse 속도 빠른것: id, class, tag
- traverse 속도 느린것: attr ([])
부모 컴포넌트에 적용된 범위 CSS는 하위 컴포넌트에도 반영된다. (CSS 범위가 자식/자손 컴포넌트까지 적용됨)
<style scoped>
.main {..}
</style>
<div class="main">..</div>
--------------------------------------------------------
// 실제 브라우저에서 보면 element에 data-v로 시작하는 속성이 추가됐음을 확인 할 수 있음.
<div data-v-1049f479 class="main">..</div>
.main[data-v-1049f479] { ...}
# CSS 모듈 (CSS Module)
<style module>로 설정 CSS 모듈은 CSS스타일을 마치 객체 처럼 다룰 수 있게 한다.
장점
- 이름 충돌이 나지 않는다.
- 클래스 선택자를 사용할 수 있다.
단점
- 자식 컴포넌트로 스타일이 전이되지 않는다.
- 비슷한 스타일을 여러 컴포넌트에서 작성할 경우 CSS 파일 크기가 커진다.
<style module>
.main {..}
</style>
------------------------------------------------------------------------------------------
<button :class="$style.main">
<button :class="[$style.box, $style.border]"> // 배열로 여러개 적용 가능
------------------------------------------------------------------------------------------
// 실행 결과
<button class="_2KXmN....."> // ... main이 아닌 충돌나지 않도록 다른 이름 사용
슬롯 (Slot)
부모 컴포넌트에서 자식 컴포넌트로 HTML 마크업을 전달할 수 있게 해준다.
- props(속성)으로 전달해야하는 정보가 HTML 태그가 포함된 문자열이라면 사용하기가 어려우므로, 여러 개의 적용하려는 CSS 클래스가 있다면 이것들을 속성을 통해 하나씩 전달하기 위해 child 컴포넌트에 많은 props가 정의되어야 하므로 보통 슬롯을 사용
# 단일 슬롯
자식 컴포넌트에 하나의 slot만 전달한다.
Child
<template>
<div> ..
<slot></slot>
</div>
</template>
Parent
<template>
<child> <div> .. </div> </child>
</template>
# 명명된 슬롯 (Named Slot)
슬롯에 이름을 부여하면 여러 개의 슬롯을 작성할 수 있다.
Child
<template>
<div id="test">
<header> <slot name="header"> </slot> </header>
<aside id="sidebar"><slot name="sidebar"></slot></aside>
...
</div>
</template>
Parent
<template>
<div id="app">
<layout>
<h1 slot="header">헤더 영역</h1> // 컴포넌트로도 처리 가능 <child1 slot="slot1">
<div slot="sidebar"><ul> .. </ul> </div>
</layout>
</div>
</template>
# 범위 슬롯 (Scoped Slot)
자식 컴포넌트에서 부모 컴포넌트로 Slot에 속성을 전달하여 부모 컴포넌트에 출력할 내용을 커스터마이징 할 수 있다.
Child
<template>
<div class="child">
x: <input .. /><br/>
<slot name="type1" :cx="x" :cy="y"></slot>
<slot name="type2" :cx="x" :cy="y"></slot>
</div>
</template>
Parent
<template>
<child>
<template slot="type1" scope="p1"> <div> {{p1.cx}} + {{p1.cy}} </div></template> // child의 x, y 속성을 cx, cy속성으로 전달받아 p1에서 참조
<template slot="type2" scope="p2"> <div> {{p2.cx}} 더하기 {{p2.cy}} </div></template>
</child>
</template>
동적 컴포넌트 (Dynamic Component)
화면의 동일한 위치에 특정 상황에 따라 각각 다른 컴포넌트를 표현해야할 경우 동적 컴포넌트를 사용한다.
<component>요소를 템플릿에 작성하고 v-bind 디렉티브를 이용해 is 특성값으로 어떤 컴포넌트를 그 위치에 나타낼지 결정한다.
<ul>
<li><a href="#" @click="changeMenu('about')">About</a></li>
<li><a href="#" @click="changeMenu('home')">home</a></li>
<li><a href="#" @click="changeMenu('contact')">Contact</a></li>
</ul>
<div class="container">
<component v-bind:is="currentView"></component>
</div>
<script>
import Home from './cmp/Home.vue'
import Contact from './cmp/Contact.vue'
import About from './cmp/About.vue'
export default {
data() { return { currentView: 'home'; } },
methods: { changeView(view) { this.currentView = view; } }
}
</script>
<keep-alive> 요소
- 매번 실행되므로(Q) <component>로 표현될 자식 컴포넌트들이 정적 콘텐츠라면 매번 실행되는 것은 효율적이지 않다. 이런 경우는 <component>요소를로 감싸서 캐싱하면 된다.
- <keep-alive> : 렌더링된 결과를 캐싱하고 사용함. (ex) 고정적인 Header와 같은 것에 사용
- 만일 특정 컴포넌트만 캐싱하거나 캐싱하고 싶지 않다면 include, exclude 특성으로 컴포넌트들을 콤마로 구분해서 나열하면 된다. 이때 지정된 이름이 있어야 하므로 각 컴포넌트,마다 name 옵션을 부여해야하며 이 이름으로 include, exclude 한다.
- name옵션을 부여하지 않으면 컴포넌트명 기준으로 name을 인식한다.
- name은 대소문자를 구분한다
<keep-alive include="aoout, home">
<component v-bind:is="currentView"></component>
</keep-alive>
재귀 컴포넌트
템플릿에서 자기 자신을 호출하는 컴포넌트.
반드시 name 옵션을 지정해야한다.
Child
<template>
<ul>
<li v-for="s in subs" v-bind:class="s.type">
{{name}}
<tree :subs="s.subs"></tree>
</li>
</ul>
</template>
<script>
export default {
name: 'tree',
props: ['subs']
}
</script>
Parent
<template>
<div>
...
<tree :subs="orgcharts"></tree>
</div>
</template>
<script>
import Tree from './Tree.vue'
export default{
name: 'aobut',
components: { Tree },
data(){
return {
orgcharts: [ { name: '서울', type: 'division', subs: [ { name: '서울 동작구팀', type: 'team'}, ..] } ... ]
}
}
참고 : Vue.js 퀵스타트
'javascript > Vue' 카테고리의 다른 글
Vue devtools 설치 및 사용 (0) | 2021.07.25 |
---|---|
Vue.js 컴포넌트 (기본) (0) | 2021.03.20 |
Vue 다이어리 만들기(Vue Diary) - vuex,vue-router,element-ui (0) | 2020.07.21 |