|
| 1 | +--- |
| 2 | +title: 컴포넌트 등록 |
| 3 | +type: guide |
| 4 | +order: 101 |
| 5 | +--- |
| 6 | + |
| 7 | +> 이 페이지는 여러분이 이미 [컴포넌트 기초](components.html)를 읽었다고 가정하고 쓴 내용입니다. 컴포넌트가 처음이라면 기초 문서를 먼저 읽으시기 바랍니다. |
| 8 | +
|
| 9 | +## 컴포넌트 이름 |
| 10 | + |
| 11 | +컴포넌트를 등록할 때는 항상 이름을 지어줘야 합니다. 예를 들어 우리가 살펴봤던 전역등록은 아래처럼 하죠. |
| 12 | + |
| 13 | +```js |
| 14 | +Vue.component('my-component-name', { /* ... */ }) |
| 15 | +``` |
| 16 | + |
| 17 | +컴포넌트의 이름은 `Vue.component`의 첫번째 인자입니다. |
| 18 | + |
| 19 | +컴포넌트에 부여한 이름은 그 컴포넌트를 어디에 쓸 지에 따라 다를 수 있습니다. 컴포넌트를 (스트링 템플릿이나 [싱글파일 컴포넌트](single-file-components.html)로 사용하지 않고) DOM에서 바로 사용할 때는 [W3C 규칙](https://html.spec.whatwg.org/multipage/custom-elements.html#valid-custom-element-name)에 따라서 사용자 정의 태그의 이름처럼 쓰는 것을 추천합니다(모두 소문자로 쓰고 단어는 하이픈(-)으로 연결하는 거죠). 이렇게 하면 지금 있거나 앞으로 작성할 HTML 엘리먼트와 충돌하는 것을 피할 수 있습니다. |
| 20 | + |
| 21 | +기타 컴포넌트 이름을 지을 때 숙지할 내용은 [스타일 가이드](../style-guide/#베이스-컴포넌트-이름-매우-추천함)를 참고해주세요. |
| 22 | + |
| 23 | + |
| 24 | +### 이름 표기법 |
| 25 | + |
| 26 | +컴포넌트 이름을 지을 때는 두 가지 방법이 있습니다. |
| 27 | + |
| 28 | + |
| 29 | +#### 케밥-표기법 |
| 30 | + |
| 31 | +```js |
| 32 | +Vue.component('my-component-name', { /* ... */ }) |
| 33 | +``` |
| 34 | + |
| 35 | +케밥-표기법으로 컴포넌트를 정의할 때는 사용자 정의 엘리먼트를 부를 때에도 `<my-component-name>`와 같이 반드시 케밥-표기법을 사용해야 합니다. |
| 36 | + |
| 37 | + |
| 38 | +#### 파스칼표기법 |
| 39 | + |
| 40 | +```js |
| 41 | +Vue.component('MyComponentName', { /* ... */ }) |
| 42 | +``` |
| 43 | + |
| 44 | +파스칼표기법으로 컴포넌트를 정의할 때는 자용자 정의 엘리먼트를 부를 때 두 가지 표기법 모두 사용할 수 있습니다. 즉 `<my-component-name>`와 `<MyComponentName>` 모두 괜찮습니다. 단, DOM에 바로 쓸 때는 케밥-표기법 이름만 가능합니다. |
| 45 | + |
| 46 | + |
| 47 | +## 전역 등록 |
| 48 | + |
| 49 | +지금까지 우리는 `Vue.component`를 이용해서만 컴포넌트를 만들었습니다. |
| 50 | + |
| 51 | +```js |
| 52 | +Vue.component('my-component-name', { |
| 53 | + // ... options ... |
| 54 | +}) |
| 55 | +``` |
| 56 | + |
| 57 | +이런 컴포넌트를 **전역 등록**되었다고 합니다. 즉 어떤 루트 Vue 인스턴스(`new Vue`)에서도 사용할 수 있는 거죠. |
| 58 | + |
| 59 | +```js |
| 60 | +Vue.component('component-a', { /* ... */ }) |
| 61 | +Vue.component('component-b', { /* ... */ }) |
| 62 | +Vue.component('component-c', { /* ... */ }) |
| 63 | + |
| 64 | +new Vue({ el: '#app' }) |
| 65 | +``` |
| 66 | + |
| 67 | +```html |
| 68 | +<div id="app"> |
| 69 | + <component-a></component-a> |
| 70 | + <component-b></component-b> |
| 71 | + <component-c></component-c> |
| 72 | +</div> |
| 73 | +``` |
| 74 | + |
| 75 | +이렇게 등록한 컴포넌트들은 모든 하위 컴포넌트에도 사용가능합니다. 즉 위의 3개 컴포넌트들은 _각각의 컴포넌트 안에서도_ 사용할 수 있습니다. |
| 76 | + |
| 77 | + |
| 78 | +## 지역 등록 |
| 79 | + |
| 80 | +전역 등록이 썩 좋기만 한 건 아닙니다. 예를 들어 웹팩같은 빌드 시스템을 사용하고 모든 컴포넌트를 전역 등록했으면 설사 어떤 컴포넌트를 더 이상 사용하지 않더라도 최종 빌드에는 들어가 있게 됩니다. 사용자가 내려받아야 하는 자바스크립트의 양이 불필요하게 커지는 거죠. |
| 81 | + |
| 82 | +이 경우에 컴포넌트를 일반 자바스크립트 객체로 정의할 수 있습니다. |
| 83 | + |
| 84 | +```js |
| 85 | +var ComponentA = { /* ... */ } |
| 86 | +var ComponentB = { /* ... */ } |
| 87 | +var ComponentC = { /* ... */ } |
| 88 | +``` |
| 89 | + |
| 90 | +그러면 사용할 컴포넌트들만 `components` 옵션을 통해 쓸 수 있습니다. |
| 91 | + |
| 92 | +```js |
| 93 | +new Vue({ |
| 94 | + el: '#app', |
| 95 | + components: { |
| 96 | + 'component-a': ComponentA, |
| 97 | + 'component-b': ComponentB |
| 98 | + } |
| 99 | +}) |
| 100 | +``` |
| 101 | + |
| 102 | +`components` 객체의 각 속성에서 키가 커스텀 엘리먼트의 이름이 되고 밸류가 사용할 컴포넌트 객체를 지정합니다. |
| 103 | + |
| 104 | +**지역 등록된 컴포넌트는 하위컴포넌트에서는 사용이 _불가능하다_**는 점을 유의해야 합니다. 예를 들어 `ComponentA`를 `ComponentB`에서 쓰고 싶다면 아래와 같이 해야 합니다. |
| 105 | + |
| 106 | +```js |
| 107 | +var ComponentA = { /* ... */ } |
| 108 | + |
| 109 | +var ComponentB = { |
| 110 | + components: { |
| 111 | + 'component-a': ComponentA |
| 112 | + }, |
| 113 | + // ... |
| 114 | +} |
| 115 | +``` |
| 116 | + |
| 117 | +바벨이나 웹팩을 이용해서 ES2015를 적용하고 있다면 싱글파일 컴포넌트를 이용해서 이렇게 할 수도 있습니다. |
| 118 | + |
| 119 | +```js |
| 120 | +import ComponentA from './ComponentA.vue' |
| 121 | + |
| 122 | +export default { |
| 123 | + components: { |
| 124 | + ComponentA |
| 125 | + }, |
| 126 | + // ... |
| 127 | +} |
| 128 | +``` |
| 129 | + |
| 130 | +ES2015 이상에서는 객체 내의 `components` 옵션에서 `ComponentA: ComponentA`라고 하지 않고 `ComponentA`라고만 해도 됩니다. 즉 키로 아래의 두 가지가 모두 가능합니다.(역자 주: `component-a: ComponentA`, `ComponentA: ComponentA`, `ComponentA`가 모두 가능합니다.) |
| 131 | + |
| 132 | +- 템플릿에서 사용할 사용자정의 엘리먼트 이름 |
| 133 | +- 컴포넌트 옵션에 들어갈 변수명 |
| 134 | + |
| 135 | + |
| 136 | +## 모듈 시스템 |
| 137 | + |
| 138 | +`import`/`require`를 이용한 모듈 시스템을 쓰지 않으면 이번 내용은 넘어가도 괜찮습니다. 만약 모듈 시스템을 쓴다면 특별한 소개와 팁을 드리도록 할게요. |
| 139 | + |
| 140 | + |
| 141 | +### 모듈 시스템에서 컴포넌트를 다른 컴포넌트에 지역적으로 등록하기 |
| 142 | + |
| 143 | +지금 읽고 있다면 당신은 모듈 시스템을 쓴다는 뜻이겠죠. 바벨이나 웹팩같은 것과 함께 말입니다. 이 경우에는 `components` 디렉토리를 만들고 각 컴포넌트들을 그 자체로 하나의 파일에 관리하는 것을 추천합니다. |
| 144 | + |
| 145 | +그러면 어떤 컴포넌트를 다른 컴포넌트에 지역적으로 등록하기 전에 사용할 컴포넌트를 가져와야 합니다. 예를 들면 `ComponentB.js`나 `ComponentB.vue`같은 파일에서 아래처럼 다른 컴포넌트를 가져오는 거죠. |
| 146 | + |
| 147 | +```js |
| 148 | +import ComponentA from './ComponentA' |
| 149 | +import ComponentC from './ComponentC' |
| 150 | + |
| 151 | +export default { |
| 152 | + components: { |
| 153 | + ComponentA, |
| 154 | + ComponentC |
| 155 | + }, |
| 156 | + // ... |
| 157 | +} |
| 158 | +``` |
| 159 | + |
| 160 | +이제 `ComponentA`와 `ComponentC 모두 `ComponentB`의 템플릿에서 사용할 수 있습니다. |
| 161 | + |
| 162 | + |
| 163 | +### 기본 컴포넌트를 자동으로 전역 등록하기 |
| 164 | + |
| 165 | +많은 컴포넌트들은 여기저기서 쓰이고 입력값이나 버튼 하나로 구성될 수도 있습니다. 이런 컴포넌트는 [기본 컴포넌트](../style-guide/#베이스-컴포넌트-이름-매우-추천함)라고 하고 여러 컴포넌트들에서 매우 빈번하게 사용합니다. |
| 166 | + |
| 167 | +그래서 많은 컴포넌트에서 긴 기본 컴포넌트 목록을 보게 되죠. |
| 168 | + |
| 169 | +```js |
| 170 | +import BaseButton from './BaseButton.vue' |
| 171 | +import BaseIcon from './BaseIcon.vue' |
| 172 | +import BaseInput from './BaseInput.vue' |
| 173 | + |
| 174 | +export default { |
| 175 | + components: { |
| 176 | + BaseButton, |
| 177 | + BaseIcon, |
| 178 | + BaseInput |
| 179 | + } |
| 180 | +} |
| 181 | +``` |
| 182 | + |
| 183 | +템플릿에서는 좀 더 짧은 마크업을 사용할 수 있습니다. |
| 184 | + |
| 185 | +```html |
| 186 | +<BaseInput |
| 187 | + v-model="searchText" |
| 188 | + @keydown.enter="search" |
| 189 | +/> |
| 190 | +<BaseButton @click="search"> |
| 191 | + <BaseIcon name="search"/> |
| 192 | +</BaseButton> |
| 193 | +``` |
| 194 | + |
| 195 | +다행히 웹팩을 쓴다면([Vue CLI 3+](https://github.com/vuejs/vue-cli), which uses Webpack internally)을 쓴다면 그 안에 내장하고 있어요) `require.context`를 써서 자주 쓰는 기본 컴포넌트들을 전역 등록할 수 있습니다. 아래의 예시는 어플리케이션의 엔트리 파일(e.g. `src/main.js`)에 기본 컴포넌트들을 전역적으로 불러오는 코드입니다. |
| 196 | + |
| 197 | +```js |
| 198 | +import Vue from 'vue' |
| 199 | +import upperFirst from 'lodash/upperFirst' |
| 200 | +import camelCase from 'lodash/camelCase' |
| 201 | + |
| 202 | +const requireComponent = require.context( |
| 203 | + // 컴포넌트들이 있는 폴더 |
| 204 | + './components', |
| 205 | + // 하위 폴더까지 포함할 지 여부 |
| 206 | + false, |
| 207 | + // 기본 컴포넌트를 찾는데 사용할 정규표현식 |
| 208 | + /Base[A-Z]\w+\.(vue|js)$/ |
| 209 | +) |
| 210 | + |
| 211 | +requireComponent.keys().forEach(fileName => { |
| 212 | + // 컴포넌트 설정 가져오기 |
| 213 | + const componentConfig = requireComponent(fileName) |
| 214 | + |
| 215 | + // 컴포넌트의 파스칼표기법 이름 가져오기 |
| 216 | + const componentName = upperFirst( |
| 217 | + camelCase( |
| 218 | + // 파일이름 앞의 `./` 등 파스칼표기법 이름에 들어갈 필요없는 |
| 219 | + // 기호들을 제거 |
| 220 | + fileName.replace(/^\.\/(.*)\.\w+$/, '$1') |
| 221 | + ) |
| 222 | + ) |
| 223 | + |
| 224 | + // 컴포넌트를 전역적으로 등록 |
| 225 | + Vue.component( |
| 226 | + componentName, |
| 227 | + // `export default`를 이용한 컴포넌트는 `.default`로 컴포넌트 |
| 228 | + // 옵션을 추출하고 그렇지 않은 컴포넌트는 모듈의 루트를 호출 |
| 229 | + componentConfig.default || componentConfig |
| 230 | + ) |
| 231 | +}) |
| 232 | +``` |
| 233 | + |
| 234 | +** 전역 등록은 (`new Vue`로) 루트 Vue 인스턴스가 만들어지기 전에 반드시 이뤄져야 한다는 것**을 기억해주시기 바랍니다. 실제 프로젝트에서 이 패턴이 어떻게 이뤄지는지 [이 예시](https://github.com/chrisvfritz/vue-enterprise-boilerplate/blob/master/src/components/_globals.js)를 참고해주세요. |
0 commit comments