개발은 재밌어야 한다
article thumbnail
Published 2021. 4. 13. 16:56
Vue.js 컴포넌트 (심화) javascript/Vue
반응형

1. 단일 컴포넌트

1.1. # 전역수준 컴포넌트 문제점

컴포넌트 관리가 어렵고 재사용성이 낮아진다.

  • 빌드 단계가 없으므로 ES2015, TypeScript와 같은 최신 버전 자바스크립트 문법을 사용할 수 없다. (ES 2015 전 문법 작성만 가능)
  • CSS를 지원하지 않는다. 컴포넌트들은 고유한 스타일 정보를 포함하는 경우가 많으나, 전역 컴포넌트에서는 CSS 스타일을 빌드하고 모듈화하는 기능을 제공하지 않는다.
    • css를 <link>방식이 아니라 모듈 처럼 참조(import)할 수 없다. → 모듈 처럼 사용할 경우 빌드 거치면 자체적으로 link 태그를 만든다.
  • 컴포넌트들의 템플릿이 작성될 때, HTML 파일 안에 여러 개의 <template/> 태그가 작성되어 식별하기 어렵다. 또한 템플릿마다 고유한 ID를 부여하고 컴포넌트들도 고유한 이름을 지정해야 한다.

1.2. # 단일 파일 컴포넌트

확장자가 .vue인 파일을 컴포넌트 단위로 생성한다. 크게 3가지로 나누어짐

  • <template>
  • <script>
  • <style> // 클래스 기반으로 작성해야 컴포넌트 기반 (모듈) 스타일 적용이 가능함.

사용할 컴포넌트는 등록해줘야 사용이 가능하다.
등록 방법은 전역 등록과 지역 등록이 있다.

dreamcoding.tistory.com/8?category=952284 참고

 

Vue.js 컴포넌트 (기본)

컴포넌트란? 컴포넌트 그 자체로 제 기능을 하며 재사용할 수 있는 컴포넌트로 구성된 대규모 응용 프로그램을 구축할 수 있게 해주는 추상적 개념이다. 기본 HTML Element를 확장하여 재사용 가능

dreamcoding.tistory.com

1.3. # 전역 컴포넌트와 차이점

  • <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> 내부에서 작성한다.

단일 컴포넌트

<javascript />
<template> <div id='app'> .. </div> </template> <script> export default { name: 'app', data() { return { msg: 'test' } } } </script> <style> #app { .. } </style>

단일 컴포넌트 사용

<javascript />
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/>' })

2. 컴포넌트 스타일

특정 컴포넌트만의 스타일 지정할 수 있으며, 다음과 같은 방법이 있다.

  • 범위 CSS (Scoped CSS)
  • CSS 모듈(CSS Module)

2.1. # 범위 CSS (Scoped CSS)

<style scoped>로 설정 특성 선택자(attribute selector)를 사용하기 때문에 브라우저에서 스타일을 적용하는 속도가 느리다. 그렇기 때문에 반드시 속도가 빠른 ID 선택자, 클래스 선택자, 태그명 선택자로 요소를 선택해 스타일을 적용하도록 해야한다.

  • traverse 속도 빠른것: id, class, tag
  • traverse 속도 느린것: attr ([])

부모 컴포넌트에 적용된 범위 CSS는 하위 컴포넌트에도 반영된다. (CSS 범위가 자식/자손 컴포넌트까지 적용됨)

3.  

<javascript />
<style scoped> .main {..} </style> <div class="main">..</div> -------------------------------------------------------- // 실제 브라우저에서 보면 element에 data-v로 시작하는 속성이 추가됐음을 확인 할 수 있음. <div data-v-1049f479 class="main">..</div> .main[data-v-1049f479] { ...}

3.1. # CSS 모듈 (CSS Module)

<style module>로 설정 CSS 모듈은 CSS스타일을 마치 객체 처럼 다룰 수 있게 한다.
장점

  • 이름 충돌이 나지 않는다.
  • 클래스 선택자를 사용할 수 있다.


단점

  • 자식 컴포넌트로 스타일이 전이되지 않는다.
  • 비슷한 스타일을 여러 컴포넌트에서 작성할 경우 CSS 파일 크기가 커진다.
<javascript />
<style module> .main {..} </style> ------------------------------------------------------------------------------------------ <button :class="$style.main"> <button :class="[$style.box, $style.border]"> // 배열로 여러개 적용 가능 ------------------------------------------------------------------------------------------ // 실행 결과 <button class="_2KXmN....."> // ... main이 아닌 충돌나지 않도록 다른 이름 사용

4. 슬롯 (Slot)

부모 컴포넌트에서 자식 컴포넌트로 HTML 마크업을 전달할 수 있게 해준다.

  • props(속성)으로 전달해야하는 정보가 HTML 태그가 포함된 문자열이라면 사용하기가 어려우므로, 여러 개의 적용하려는 CSS 클래스가 있다면 이것들을 속성을 통해 하나씩 전달하기 위해 child 컴포넌트에 많은 props가 정의되어야 하므로 보통 슬롯을 사용

4.1. # 단일 슬롯

자식 컴포넌트에 하나의 slot만 전달한다.

Child

<javascript />
<template> <div> .. <slot></slot> </div> </template>

Parent

<javascript />
<template> <child> <div> .. </div> </child> </template>

 

4.2. # 명명된 슬롯 (Named Slot)

슬롯에 이름을 부여하면 여러 개의 슬롯을 작성할 수 있다.

Child

<javascript />
<template> <div id="test"> <header> <slot name="header"> </slot> </header> <aside id="sidebar"><slot name="sidebar"></slot></aside> ... </div> </template>


Parent

<javascript />
<template> <div id="app"> <layout> <h1 slot="header">헤더 영역</h1> // 컴포넌트로도 처리 가능 <child1 slot="slot1"> <div slot="sidebar"><ul> .. </ul> </div> </layout> </div> </template>

4.3. # 범위 슬롯 (Scoped Slot)

자식 컴포넌트에서 부모 컴포넌트로 Slot에 속성을 전달하여 부모 컴포넌트에 출력할 내용을 커스터마이징 할 수 있다.

Child

<javascript />
<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

<javascript />
<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>

5. 동적 컴포넌트 (Dynamic Component)

화면의 동일한 위치에 특정 상황에 따라 각각 다른 컴포넌트를 표현해야할 경우 동적 컴포넌트를 사용한다.
<component>요소를 템플릿에 작성하고 v-bind 디렉티브를 이용해 is 특성값으로 어떤 컴포넌트를 그 위치에 나타낼지 결정한다.

<javascript />
<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은 대소문자를 구분한다
<javascript />
<keep-alive include="aoout, home"> <component v-bind:is="currentView"></component> </keep-alive>

6. 재귀 컴포넌트

템플릿에서 자기 자신을 호출하는 컴포넌트.
반드시 name 옵션을 지정해야한다.

Child

<javascript />
<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

<javascript />
<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 퀵스타트

반응형
profile

개발은 재밌어야 한다

@ghyeong

포스팅이 좋았다면 "좋아요❤️" 또는 "구독👍🏻" 해주세요!