From 5b4fb4b912ef3d47179a27b129e18d58e66195dc Mon Sep 17 00:00:00 2001 From: "Jisung, Ahn" Date: Wed, 29 Jul 2020 04:05:03 +0000 Subject: [PATCH 001/416] Translate README.md via GitLocalize --- ko-KR/README.md | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) create mode 100644 ko-KR/README.md diff --git a/ko-KR/README.md b/ko-KR/README.md new file mode 100644 index 000000000..cc65b3f7a --- /dev/null +++ b/ko-KR/README.md @@ -0,0 +1,33 @@ +# v3.vuejs.org + +이 사이트는 [VuePres](https://vuepress.vuejs.org/)s 로 구축 되었습니다 . 사이트 컨텐츠는에 `src` 위치한 마크 다운 형식으로 작성됩니다 + +## 문서 작성 + +문서 작성 및 유지 관리에 대한 규칙 및 권장 사항 은 [Vue Docs Writing Guide](https://v3.vuejs.org/guide/writing-guide.html) 를 참조하십시오 . + +> The docs are in beta: The team is currently in the midst of changes and we are not ready for additional contributions yet. All content is subject to change. If you see a problem that you would like to bring to our attention, please [create an issue](https://github.com/vuejs/docs-next/issues/new) and we will get to it when we can. You may want to wait until the content is finalized, though. + +## 개발하기 + +1. 저장소를 복제합니다 + +```bash +git clone git@github.com:vuejs/docs-next.git +``` + +1. 의존성을 설치합니다 + +```bash +yarn # or npm install +``` + +1. 로컬 개발환경을 시작합니다. + +```bash +yarn serve +``` + +## 배포하기 + +The site is automatically deployed when commits land in `master`, via [Netlify](https://www.netlify.com/). From 1b352a5a5ddac73ec2c0edfe1792d1180c343a3a Mon Sep 17 00:00:00 2001 From: Terrorboy Date: Wed, 5 Aug 2020 00:47:24 +0000 Subject: [PATCH 002/416] Translate README.md via GitLocalize --- ko-KR/README.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/ko-KR/README.md b/ko-KR/README.md index cc65b3f7a..610c7893a 100644 --- a/ko-KR/README.md +++ b/ko-KR/README.md @@ -1,12 +1,12 @@ # v3.vuejs.org -이 사이트는 [VuePres](https://vuepress.vuejs.org/)s 로 구축 되었습니다 . 사이트 컨텐츠는에 `src` 위치한 마크 다운 형식으로 작성됩니다 +이 사이트는 [VuePress](https://vuepress.vuejs.org/) 로 구축 되었습니다 . 사이트 컨텐츠는에 `src` 위치한 마크 다운 형식으로 작성됩니다 ## 문서 작성 문서 작성 및 유지 관리에 대한 규칙 및 권장 사항 은 [Vue Docs Writing Guide](https://v3.vuejs.org/guide/writing-guide.html) 를 참조하십시오 . -> The docs are in beta: The team is currently in the midst of changes and we are not ready for additional contributions yet. All content is subject to change. If you see a problem that you would like to bring to our attention, please [create an issue](https://github.com/vuejs/docs-next/issues/new) and we will get to it when we can. You may want to wait until the content is finalized, though. +> 문서는 베타 버전입니다 : 팀은 현재 수정 중에 있으며, 아직 추가 공헌 준비하지 않습니다. 모든 컨텐츠는 변경 될 수 있습니다. 신경 쓰이는 문제가 있으시면, [이슈](https://github.com/vuejs/docs-next/issues/new)로 등록해주세요. 가능한 한 대응하겠습니다. 그러나 콘텐츠가 완성 될 때까지 기다리는 것이 좋습니다. ## 개발하기 @@ -25,9 +25,9 @@ yarn # or npm install 1. 로컬 개발환경을 시작합니다. ```bash -yarn serve +yarn serve # or npm run serve ``` ## 배포하기 -The site is automatically deployed when commits land in `master`, via [Netlify](https://www.netlify.com/). +`master`에 커밋을 하면 [Netlify](https://www.netlify.com/)를 통하여 자동배포 됩니다 From aa9cc824293c11d4dbc867a8c83dbffeae5d0965 Mon Sep 17 00:00:00 2001 From: Terrorboy Date: Wed, 5 Aug 2020 04:47:25 +0000 Subject: [PATCH 003/416] Translate async-components.md via GitLocalize --- ko-KR/src/guide/migration/async-components.md | 93 +++++++++++++++++++ 1 file changed, 93 insertions(+) create mode 100644 ko-KR/src/guide/migration/async-components.md diff --git a/ko-KR/src/guide/migration/async-components.md b/ko-KR/src/guide/migration/async-components.md new file mode 100644 index 000000000..c70c6c659 --- /dev/null +++ b/ko-KR/src/guide/migration/async-components.md @@ -0,0 +1,93 @@ +--- +badges: +- new +--- + +# 비동기 컴포넌트 + +## 개요 + +변경내용: + +- 비동기 컴포넌트를 명시적으로 정의하는 새로운 `defineAsyncComponent` 헬퍼 메소드 +- `component` 옵션명을 `loader`로 변경 +- Loader 함수는 `resolve` 및 `reject`를 인수를 받지 않으며 Promise를 반환합니다. + +더 자세한 설명은 계속 읽으십시오! + +## 서론 + +이전에는 다음과 같이 promise를 반환하는 함수로 컴포넌트를 정의하여 비동기 컴포넌트를 만들었습니다. + +```js +const asyncPage = () => import('./NextPage.vue') +``` + +또는, 옵션을 통하여 컴포넌트 구문을 설정합니다. + +```js +const asyncPage = { + component: () => import('./NextPage.vue'), + delay: 200, + timeout: 3000, + error: ErrorComponent, + loading: LoadingComponent +} +``` + +## 3.x 구문 + +Vue 3의 함수형 컴포넌트는 순수 함수로 정의되어 있으므로 비동기 컴포넌트 정의는 새로운 `defineAsyncComponent` 헬퍼에서 래핑하여 명시적으로 정의해야 합니다. + +```js +import { defineAsyncComponent } from 'vue' +import ErrorComponent from './components/ErrorComponent.vue' +import LoadingComponent from './components/LoadingComponent.vue' + +// Async component without options +const asyncPage = defineAsyncComponent(() => import('./NextPage.vue')) + +// Async component with options +const asyncPageWithOptions = defineAsyncComponent({ + loader: () => import('./NextPage.vue'), + delay: 200, + timeout: 3000, + errorComponent: ErrorComponent, + loadingComponent: LoadingComponent +}) +``` + +2.x에서 추가된 또 하나의 변화는 컴포넌트(`component`)를 직접 제공 할 수 없는 것을 정확하게 전달하기 위해 컴포넌트 옵션의 이름이 로더(`loader`)로 변경된 것입니다. + +```js{4} +import { defineAsyncComponent } from 'vue' + +const asyncPageWithOptions = defineAsyncComponent({ + loader: () => import('./NextPage.vue'), + delay: 200, + timeout: 3000, + error: ErrorComponent, + loading: LoadingComponent +}) +``` + +또한, 2.x와 달리 로더 함수는 `resolve`와 `reject` 인수를 받지 않으며 항상 Promise를 반환해야 합니다. + +```js +// 2.x version +const oldAsyncComponent = (resolve, reject) => { + /* ... */ +} + +// 3.x version +const asyncComponent = defineAsyncComponent( + () => + new Promise((resolve, reject) => { + /* ... */ + }) +) +``` + +비동기 컴포넌트 사용에 대한 자세한 내용은 다음을 참조하십시오. + +- [가이드 : 동적 & 비동기 컴포넌트](/guide/component-dynamic-async.html#dynamic-components-with-keep-alive) From 8a193c939633618d7e3a0bd7cef5935a738f642f Mon Sep 17 00:00:00 2001 From: kdeun1 Date: Wed, 5 Aug 2020 11:31:33 +0000 Subject: [PATCH 004/416] Translate forms.md via GitLocalize --- ko-KR/src/guide/forms.md | 278 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 278 insertions(+) create mode 100644 ko-KR/src/guide/forms.md diff --git a/ko-KR/src/guide/forms.md b/ko-KR/src/guide/forms.md new file mode 100644 index 000000000..19b7562ac --- /dev/null +++ b/ko-KR/src/guide/forms.md @@ -0,0 +1,278 @@ +# 폼 입력 바인딩 + +## 기본 사용법 + +`v-model` 디렉티브를 사용하여 input, textarea, select 요소들에 양방향 데이터 바인딩을 생성할 수 있습니다. v-model 디렉티브는 `input type` 요소를 변경하는 올바른 방법을 자동으로 선택합니다. 약간 이상하지만, `v-model`은 기본적으로 사용자 입력 이벤트에 대한 데이터를 업데이트하는 “syntax sugar”이며, 일부 경우에는 특별한 주의를 해야합니다. + +::: tip Note `v-model`은 모든 form 엘리먼트의 초기 `value`와 `checked` 그리고 `selected` 속성을 무시합니다. 항상 Vue 인스턴스 데이터를 원본 소스로 취급합니다. 컴포넌트의 `data` 옵션 안에 있는 JavaScript에서 초기값을 선언해야합니다. ::: + +`v-model`은 내부적으로 서로 다른 속성을 사용하고 서로 다른 입력 요소에 대해 서로 다른 이벤트를 전송합니다 : + +- `text` 와 `textarea` 태그는 value속성과 input이벤트를 사용합니다. +- 체크박스들과 라디오버튼들은 `checked` 속성과 `change` 이벤트를 사용합니다. +- Select 태그는 `value` 를 prop으로, `change`를 이벤트로 사용합니다. + + ::: tip Note [IME](https://en.wikipedia.org/wiki/Input_method) (중국어, 일본어, 한국어 등)가 필요한 언어의 경우 IME 중 `v-model`이 업데이트 되지 않습니다. 이러한 업데이트를 처리하려면 `input` 이벤트를 대신 사용하십시오. ::: + +### 문자열 + +```html + +

메시지: {{ message }}

+``` + +

See the Pen Handling forms: basic v-model by Vue (@Vue) on CodePen.

+ +### 여러 줄을 가진 문장 + +```html +여러 줄을 가지는 메시지: +

{{ message }}

+
+ +``` + +

See the Pen Handling forms: textarea by Vue (@Vue) on CodePen.

+ +textarea의 텍스트 보간은 작동하지 않습니다. 대신 `v-model`를 사용하십시오. + +```html + + + + + +``` + +### 체크박스 + +하나의 체크박스는 단일 boolean 값을 가집니다: + +```html + + +``` + +

See the Pen Handling forms: checkbox by Vue (@Vue) on CodePen.

+ +여러개의 체크박스에 동일한 배열을 바인딩할 수 있습니다: + +```html +
+ + + + + + +
+ Checked names: {{ checkedNames }} +
+``` + +```js +Vue.createApp({ + data() { + return { + checkedNames: [] + } + } +}).mount('#v-model-multiple-checkboxes') +``` + +

See the Pen Handling forms: multiple checkboxes by Vue (@Vue) on CodePen.

+ +### 라디오 + +```html +
+ + +
+ + +
+ Picked: {{ picked }} +
+``` + +```js +Vue.createApp({ + data() { + return { + picked: '' + } + } +}).mount('#v-model-radiobutton') +``` + +

See the Pen Handling forms: radiobutton by Vue (@Vue) on CodePen.

+ +### 셀렉트 + +단일 셀렉트: + +```html +
+ + Selected: {{ selected }} +
+``` + +```js +Vue.createApp({ + data() { + return { + selected: '' + } + } +}).mount('#v-model-select') +``` + +

See the Pen Handling forms: select by Vue (@Vue) on CodePen.

+ +:::tip Note `v-model` 표현식의 초기 값이 어떤 옵션에도 없으면, ` + + + + +
+Selected: {{ selected }} +``` + +

See the Pen Handling forms: select bound to array by Vue (@Vue) on CodePen.

+ +`v-for` 를 이용한 동적 옵션 렌더링: + +```html +
+ + Selected: {{ selected }} +
+``` + +```js +Vue.createApp({ + data() { + return { + selected: 'A', + options: [ + { text: 'One', value: 'A' }, + { text: 'Two', value: 'B' }, + { text: 'Three', value: 'C' } + ] + } + } +}).mount('#v-model-select-dynamic') +``` + +

See the Pen Handling forms: select with dynamic options by Vue (@Vue) on CodePen.

+ +## 값 바인딩하기 + +라디오, 체크박스 및 셀렉트 옵션의 경우, `v-model` 바인딩 값은 보통 정적인 문자열(또는 체크 박스의 boolean) 입니다. + +```html + + + + + + + + +``` + +그러나 때로는 현재 활성 인스턴스의 동적 속성에 값을 바인딩하려고 할 때, `v-bind`를 사용할 수 있습니다. 또한, `v-bind`를 사용하면 입력 값을 문자열이 아닌 값에 바인딩 할 수 있습니다. + +### 체크박스 + +```html + +``` + +```js +// 체크된 경우: +vm.toggle === 'yes' +// 체크되지 않은 경우: +vm.toggle === 'no' +``` + +:::tip Tip 브라우저는 폼 전송(form submission) 시 체크되지 않은 박스를 포함하지 않기 때문에, `true-value` 와 `false-value` 속성은 입력의 `value` 특성에 영향을 주지 않습니다. 두 값("예" 또는 "아니오") 중 하나가 폼을 통해 전송되려면 라디오를 대신 사용하십시오. ::: + +### 라디오 + +```html + +``` + +```js +// 체크된 경우: +vm.pick === vm.a +``` + +### 셀렉트 옵션 + +```html + +``` + +```js +// 선택된 경우: +typeof vm.selected // => 'object' +vm.selected.number // => 123 +``` + +## 수식어 + +### `.lazy` + +기본적으로, `v-model`은 각 `input` 이벤트 후 입력과 데이터를 동기화 합니다. (단, [앞에서 설명](#vmodel-ime-tip)한 IME 구성은 제외됩니다.). `lazy` 수식어를 추가하여 `change`이벤트 이후에 동기화 할 수 있습니다.: + +```html + + +``` + +### `.number` + +사용자 입력이 자동으로 숫자로 형변환 되기를 원하면, `v-model`이 관리하는 input에 `number` 수식어를 추가하면 됩니다. + +```html + +``` + +`type="number"`를 사용하는 경우에 HTML 입력 요소의 값은 항상 문자열을 반영하기 때문에 종종 유용합니다. 만약, 값이 `parseFloat()`에 의해서 분석할 수 없는 경우, 원래의 값이 리턴됩니다. + +### `.trim` + +사용자 입력이 자동으로 숫자로 형변환 되기를 원하면, `v-model`이 관리하는 input에 `number` 수식어를 추가하면 됩니다. + +```html + +``` + +## 컴포넌트에서의 `v-model` + +> 아직 Vue의 구성 요소에 익숙하지 않다면 지금은 넘어가도 됩니다. + +HTML의 기본 제공(built-in) input type은 항상 사용자의 요구를 만족시킬 수는 없습니다. 다행히, Vue 컴포넌트는 완전히 사용자 정의된 동작의 재사용 가능한 input을 만들 수 있습니다. 이 input은 `v-model`에도 작동합니다! 자세한 내용은 컴포넌트 가이드의 [사용자 정의 입력](./component-basics.html#using-v-model-on-components)을 참조하십시오. From 9f06422760e2e21504d1c7f758d42f37dd34013f Mon Sep 17 00:00:00 2001 From: Terrorboy Date: Fri, 7 Aug 2020 07:17:02 +0000 Subject: [PATCH 005/416] Translate async-components.md via GitLocalize --- ko-KR/src/guide/migration/async-components.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/ko-KR/src/guide/migration/async-components.md b/ko-KR/src/guide/migration/async-components.md index c70c6c659..25bf1e3b9 100644 --- a/ko-KR/src/guide/migration/async-components.md +++ b/ko-KR/src/guide/migration/async-components.md @@ -44,10 +44,10 @@ import { defineAsyncComponent } from 'vue' import ErrorComponent from './components/ErrorComponent.vue' import LoadingComponent from './components/LoadingComponent.vue' -// Async component without options +// 옵션이 없는 비동기 컴포넌트 const asyncPage = defineAsyncComponent(() => import('./NextPage.vue')) -// Async component with options +// 옵션이 있는 비동기 컴포넌트 const asyncPageWithOptions = defineAsyncComponent({ loader: () => import('./NextPage.vue'), delay: 200, @@ -74,12 +74,12 @@ const asyncPageWithOptions = defineAsyncComponent({ 또한, 2.x와 달리 로더 함수는 `resolve`와 `reject` 인수를 받지 않으며 항상 Promise를 반환해야 합니다. ```js -// 2.x version +// 2.x 버전 const oldAsyncComponent = (resolve, reject) => { /* ... */ } -// 3.x version +// 3.x 버전 const asyncComponent = defineAsyncComponent( () => new Promise((resolve, reject) => { From b93c6137683e3171a74871a779976647e074f88d Mon Sep 17 00:00:00 2001 From: kdeun1 Date: Fri, 7 Aug 2020 07:20:08 +0000 Subject: [PATCH 006/416] Translate composition-api-introduction.md via GitLocalize --- .../src/guide/composition-api-introduction.md | 521 ++++++++++++++++++ 1 file changed, 521 insertions(+) create mode 100644 ko-KR/src/guide/composition-api-introduction.md diff --git a/ko-KR/src/guide/composition-api-introduction.md b/ko-KR/src/guide/composition-api-introduction.md new file mode 100644 index 000000000..81daf44c3 --- /dev/null +++ b/ko-KR/src/guide/composition-api-introduction.md @@ -0,0 +1,521 @@ +# 소개 + +## 컴포지션 API가 필요한 이유 + +::: tip Note 해당 문서에서 여기까지 읽으셨다면, [Vue의 기초](introduction.md)와 [컴포넌트 생성하기](component-basics.md)에 익숙해야합니다. ::: + +Vue 컴포넌트를 만들면 재사용 가능한 코드 조각으로 결합되어진 인터페이스의 반복가능한 부분들을 추출할 수 있습니다. 이것만으로도 어플리케이션에서 유지관리성과 유연성을 얻을 수 있습니다. 그러나, 우리들은 어플리케이션이 엄청 커서 수 백개의 컴포넌트를 생각하면 충분하지 않다는 것을 경험적으로 느꼈습니다. 이러한 대규모 어플리케이션을 다룰 때는 코드 공유와 재사용이 특히 중요합니다. + +앱에서 특정 사용자의 레포지토리 목록을 보여준다고 가정해봅시다. 또한, 검색과 필터 기능을 적용하려고 합니다. 이 화면을 처리하는 컴포넌트는 다음과 같습니다: + +```js +// src/components/UserRepositories.vue + +export default { + components: { RepositoriesFilters, RepositoriesSortBy, RepositoriesList }, + props: { + user: { type: String } + }, + data () { + return { + repositories: [], // 1 + filters: { ... }, // 3 + searchQuery: '' // 2 + } + }, + computed: { + filteredRepositories () { ... }, // 3 + repositoriesMatchingSearchQuery () { ... }, // 2 + }, + watch: { + user: 'getUserRepositories' // 1 + }, + methods: { + getUserRepositories () { + // `this.user`를 사용해서 유저 레포지토리 가져오기 + }, // 2 + updateFilters () { ... }, // 3 + }, + mounted () { + this.getUserRepositories() // 1 + } +} +``` + +이 컴포넌트가 맡은 여러가지 일들: + +1. 사용자 이름에 대한 외부 API로 레포지토리 가져오기와 사용자가 변경 될 때마다 갱신하기 +2. `searchQuery` 문자열을 사용하여 레포지토리 검색하기 +3. `filters` 객체를 사용하여 레포지토리 필터링하기 + +대부분의 경우 컴포넌트의 옵션들(`data`, `computed`, `methods`, `watch`) 로 논리를 구성할 수 있습니다. 하지만, 컴포넌트가 커지면 **논리적 관심사** 목록도 또한 커집니다. 이로 인해 특히 처음부터 작성하지 않은 사람들에게는 읽고 이해하기 어려운 컴포넌트로 여겨질 수 있습니다. + +![Vue Option API: Code grouped by option type](https://user-images.githubusercontent.com/499550/62783021-7ce24400-ba89-11e9-9dd3-36f4f6b1fae2.png) + +**논리적 관심사**를 그룹화된 색상으로 표현한 커다란 컴포넌트의 예입니다. + +이러한 단편화로 인해 복잡한 컴포넌트를 이해하고 유지하기가 어렵니다. 옵션의 분리는 근본적인 논리적 관심사를 애매하게 만듭니다. 또한, 하나의 논리적 문제에 대해 작업을 할 때, 관련 코드의 옵션 블록을 지속적으로 "점프"해야합니다.
([역주] options-based API의 경우 prop, data, computed, hook 등의 옵션(또는 속성)의 규칙을 지켜서 작성해야합니다. 코드를 이해하기 위해 관련 옵션들을 위, 아래로 이동(스크롤)하여 코드를 보는 행동을 "점프"라고 표현하고 있습니다. 논리적인 관점 단위로 개발을 하려고 해도 이 옵션의 규칙을 지켜야하고 더 많은 논리 주제가 추가될 수록 코드의 양이 많아져 가독성이 떨어지고 유지보수성이 낮아집니다. 이를 보완할 수 있는 방법으로 Composition API를 제시하고 있습니다.) + +동일한 논리적 관심사와 관련있는 코드를 함께 배치할 수 있다면 더 좋을 것입니다. 이것이 바로 Composition API가 할 수 있는 일입니다. + +## Composition API 기초 + +이제 우리는 **왜**, **어떻게** 해야할지를 알았습니다. Composition API 작업을 시작하려면, 우선 실제로 사용할 수 있는 장소가 필요합니다. Vue 컴포넌트에서는 이 위치를 `setup` 이라고 부릅니다.
([역주] setup을 번역하지 않은 이유는 실제로 Composition API 내에서 setup()함수를 사용하기 때문입니다.) + +### `setup` 컴포넌트 옵션 + +새로운 `setup` 컴포넌트 옵션은 컴포넌트가 생성되기 **전**에, `props`가 한번 resolved될 때 실행됩니다. 그리고 composition API의 진입점 역할을 합니다. + +::: warning `setup`이 실행될 때, 컴포넌트 인스턴스가 아직 생성되지않아 `setup`옵션 내에 `this`가 존재하지 않습니다. 즉, `props`를 제외하고, 컴포넌트 내 다른 속성에 접근할 수 없습니다 – **local state**, **computed properties** 또는 **methods**. ::: + +`setup` 옵션은 [나중에](composition-api-setup.html#arguments) 언급할 `props` 와 `context`에 접근하는 펑션이어야합니다. 또한, `setup`에서 반환된 모든 것은 컴포넌트의 템플릿뿐만 아니라 나머지 컴포넌트 (computed properties, methods, 라이프사이클 훅 등)에 노출됩니다. + +컴포넌트에 `setup`을 추가해봅시다: + +```js +// src/components/UserRepositories.vue + +export default { + components: { RepositoriesFilters, RepositoriesSortBy, RepositoriesList }, + props: { + user: { type: String } + }, + setup(props) { + console.log(props) // { user: '' } + + return {} // 여기서 반환된 내용은 컴포넌트의 "rest"에서 사용할 수 있습니다 + } + // 컴포넌트의 "rest" 부분 +} +``` + +이제 첫번째 논리적 관심사를 추출해보겠습니다. (원본 스니펫에서 "1"이라고 표시). + +> 1. 해당 사용자 이름에 추정되는 외부 API에서 레포지토리 가져오기와 사용자가 변경 될 때마다 새로고침하기 + +가장 분명한 부분부터 시작하겠습니다: + +- 레포지토리 목록 +- 레포지토리 목록을 업데이트하는 펑션 +- 다른 컴포넌트 옵션으로 접근할 수 있도록 리스트와 펑션 반환 + +```js +// src/components/UserRepositories.vue `setup` 펑션 +import { fetchUserRepositories } from '@/api/repositories' + +// 컴포넌트 내부 +setup (props) { + let repositories = [] + const getUserRepositories = async () => { + repositories = await fetchUserRepositories(props.user) + } + + return { + repositories, + getUserRepositories // 반환된 함수는 메소드와 동일하게 동작합니다 + } +} +``` + +`repositories` 변수는 아직 반응형이 아니기 때문에 아직 작동하지 않는 것을 빼면 시작점입니다. 즉, 사용자 관점에서는 레포지토리 목록은 비어있습니다. 고쳐봅시다! + +### `ref`가 있는 반응성 변수 + +Vue 3.0에서는 다음과 같이 새로운 `ref` 펑션을 사용하여 어디서나 변수를 반응성있도록 만들 수 있습니다: + +```js +import { ref } from 'vue' + +const counter = ref(0) +``` + +`ref`는 전달인자를 받고, 반응성 변수의 값에 접근하거나 변경할 수 있는 `value` 속성을 가진 객체를 반환합니다: + +```js +import { ref } from 'vue' + +const counter = ref(0) + +console.log(counter) // { value: 0 } +console.log(counter.value) // 0 + +counter.value++ +console.log(counter.value) // 1 +``` + +객체 안에 값을 감싸는 것은 불필요할 수 있지만, JavaScript 에서 다른 데이터 타입에 걸쳐 동작을 통일시켜야합니다. JavaScript에서는 `Number` 나 `String` 과 같은 원시 타입(primitive types)은 참조에 의한 전달(pass by reference)이 아니라 값에 의한 전달(pass by value)이기 때문입니다: + +![Pass by reference vs pass by value](https://blog.penjee.com/wp-content/uploads/2015/02/pass-by-reference-vs-pass-by-value-animation.gif) + +모든 값을 감싸는 래퍼 객체(wrapper object)를 가지고 있으면 어딘가에서 반응성을 잃어버릴 염려없이 전체 앱에서 안전하게 전달할 수 있습니다. + +::: tip Note 다시말해, `ref` 는 값에 **반응형 참조**를 만듭니다. **참조** 작업의 개념은 Composition API 전체에서 종종 사용될 것입니다. ::: + +예시로 넘어와서, 반응성이 있는 `repositories` 변수를 생성해봅시다: + +```js +// src/components/UserRepositories.vue `setup` 펑션 +import { fetchUserRepositories } from '@/api/repositories' +import { ref } from 'vue' + +// 컴포넌트 내부 +setup (props) { + const repositories = ref([]) + const getUserRepositories = async () => { + repositories.value = await fetchUserRepositories(props.user) + } + + return { + repositories, + getUserRepositories + } +} +``` + +끝났습니다! 이제는 `getUserRepositories`를 호출할 때 마다 `repositories`는 변경될 것이고, 변경사항을 반영하기 위해서 화면은 업데이트될 것입니다. 컴포넌트는 이제 다음과 같아야합니다: + +```js +// src/components/UserRepositories.vue +import { fetchUserRepositories } from '@/api/repositories' +import { ref } from 'vue' + +export default { + components: { RepositoriesFilters, RepositoriesSortBy, RepositoriesList }, + props: { + user: { type: String } + }, + setup (props) { + const repositories = ref([]) + const getUserRepositories = async () => { + repositories.value = await fetchUserRepositories(props.user) + } + + return { + repositories, + getUserRepositories + } + }, + data () { + return { + filters: { ... }, // 3 + searchQuery: '' // 2 + } + }, + computed: { + filteredRepositories () { ... }, // 3 + repositoriesMatchingSearchQuery () { ... }, // 2 + }, + watch: { + user: 'getUserRepositories' // 1 + }, + methods: { + updateFilters () { ... }, // 3 + }, + mounted () { + this.getUserRepositories() // 1 + } +} +``` + +첫번째 논리적 관심사 중 몇 가지를 `setup` 메소드 안에 서로 가까이 옮겼습니다. 이제 남은 것은 `mounted` 에서 `getUserRepositories` 를 호출하는 것과 `user` props가 변경될 때마다 감시자(watcher)를 세팅하는 것입니다. + +라이프사이클 훅으로 시작할 것입니다. + +### `setup` 안에 라이프사이클 훅 등록 + +Options API와 비교하여 Composition API 형태를 완벽하게 만들기 위해서, `setup` 안에 라이프사이클 훅을 등록하는 방법도 필요합니다. Vue로부터 export한 몇가지 새로운 펑션 덕분에 가능합니다. Composition API의 라이프사이클 훅은 Options API의 라이프사이클 훅의 이름과 동일하지만, 접두사 `on`이 붙습니다. 예) `mounted` -> `onMounted`. + +이 펑션은 컴포넌트에 의해 훅이 호출될 때, 실행될 콜백을 받습니다. + +`setup` 펑션에 라이프사이클 훅을 추가해봅시다: + +```js +// src/components/UserRepositories.vue `setup` function +import { fetchUserRepositories } from '@/api/repositories' +import { ref, onMounted } from 'vue' + +// 컴포넌트 내부 +setup (props) { + const repositories = ref([]) + const getUserRepositories = async () => { + repositories.value = await fetchUserRepositories(props.user) + } + + onMounted(getUserRepositories) // `mounted`에서 `getUserRepositories` 호출 + + return { + repositories, + getUserRepositories + } +} +``` + +이제 `user` prop의 변경사항에 대해 반응이 필요합니다. 이를 위해 독립적인 `watch` 펑션을 사용해야합니다. + +### `watch`를 사용하여 변화에 반응하기 + +`watch` 옵션을 사용하여 컴포넌트 내부의 `user` 속성에 감시자를 설정하는 것과 마찬가지로, Vue에서 import한 `watch`펑션을 사용하여 동일한 작업을 수행할 수 있습니다. 3가지 전달인자를 허용합니다: + +- 감시를 원하는 **반응성 참조**나 게터 펑션
(source) +- 콜백 (`(value, oldValue, onInvalidate) => void` 형태의 callback) +- 선택적인 구성 옵션 (immediate나 deep과 같은 watchOptions) + +**작동 방식을 간단히 살펴보겠습니다.** + +```js +import { ref, watch } from 'vue' + +const counter = ref(0) +watch(counter, (newValue, oldValue) => { + console.log('새로운 counter 값: ' + counter.value) +}) +``` + +`counter`가 수정 될 때마다 (예: `counter.value = 5`), watch는 트리거하고 두번째 전달인자인 콜백을 실행합니다. 이 경우 콘솔에 `'새로운 counter 값: 5'`라고 로그가 남겨집니다. + +**아래는 Options API에 해당하는 코드입니다:** + +```js +export default { + data() { + return { + counter: 0 + } + }, + watch: { + counter(newValue, oldValue) { + console.log('새로운 counter 값: ' + this.counter) + } + } +} +``` + +`watch`에 대한 자세한 내용은 [심층 가이드]()를 참조하세요. + +**이제 예시를 적용해봅시다:** + +```js +// src/components/UserRepositories.vue `setup` 펑션 +import { fetchUserRepositories } from '@/api/repositories' +import { ref, onMounted, watch, toRefs } from 'vue' + +// 컴포넌트 내부 +setup (props) { + // `props.user`에 참조 .value속성에 접근하여 `user.value`로 변경 + const { user } = toRefs(props) + + const repositories = ref([]) + const getUserRepositories = async () => { + // `props.user`의 참조 value에 접근하기 위해서 `user.value`로 변경 + repositories.value = await fetchUserRepositories(user.value) + } + + onMounted(getUserRepositories) + + // props로 받고 반응성참조가 된 user에 감시자를 세팅 + watch(user, getUserRepositories) + + return { + repositories, + getUserRepositories + } +} +``` + +`setup` 상단에 `toRefs`가 사용된 것을 보셨을 것입니다. 이는 감시자가 `user` prop에 대한 변경사항에 반응을 보장하기 위한것이다. + +이러한 변경 사항이 적용되면, 첫번째 논리적 관심사 전체가 한 곳으로 이동되었습니다. 이제는 두번째 관심사 (computed 속성으로 `searchQuery`를 기반으로 한 필터링)에 대해 동일한 작업을 할 수 있습니다. + +### 독립형 `computed` 속성 + +`ref`와 `watch`와 마찬가지로, computed 속성은 Vue에서 import한 `computed` 펑션으로 Vue 컴포넌트 외부에서도 computed 속성을 사용할 수 있습니다. counter 예제로 돌아가봅시다: + +```js +import { ref, computed } from 'vue' + +const counter = ref(0) +const twiceTheCounter = computed(() => counter.value * 2) + +counter.value++ +console.log(counter.value) // 1 +console.log(twiceTheCounter.value) // 2 +``` + +여기, `computed` 펑션은`computed`의 첫번째 인자를 전달된 게터와 같은 콜백의 결과에 대한 *읽기 전용* **반응성 참조**를 리턴합니다. 새로 생성된 computed 변수의 **value**에 접근하려면, `ref`와 마찬가지로 `.value` 속성을 사용해야합니다.
([역주] 함수에서 반환될 때나 속성으로 할당될 때 반응성을 잃어버리기 때문에, 실제 값을 객체(.value 속성 존재)에 래핑하고 해당 객체를 리턴하여 사용하는 ref()와 사용법이 동일합니다.) + +검색 기능을 `setup`안으로 옮겨보겠습니다: + +```js +// src/components/UserRepositories.vue `setup` 펑션 +import { fetchUserRepositories } from '@/api/repositories' +import { ref, onMounted, watch, toRefs, computed } from 'vue' + +// 컴포넌트 내부 +setup (props) { + // `toRefs`를 사용하여 props의 `user`속성에 반응성 참조를 생성 + const { user } = toRefs(props) + + const repositories = ref([]) + const getUserRepositories = async () => { + // `props.user`에 참조 .value속성에 접근하여 `user.value`로 변경 + repositories.value = await fetchUserRepositories(user.value) + } + + onMounted(getUserRepositories) + + // props로 받고 반응성참조가 된 user에 감시자를 세팅 + watch(user, getUserRepositories) + + const searchQuery = ref('') + const repositoriesMatchingSearchQuery = computed(() => { + return repositories.value.filter( + repository => repository.name.includes(searchQuery.value) + ) + }) + + return { + repositories, + getUserRepositories, + searchQuery, + repositoriesMatchingSearchQuery + } +} +``` + +다른 **논리적 관심사**에 대해서도 동일한 작업을 할 수 있지만, *단순히 코드를 `setup`옵션으로 옮기고 매우 크게 만드는 것 아닌가요? *라고 질문을 할 수 있습니다. 네. 사실입니다. 그렇기 때문에, 다른 일을 수행하기 전에 위 코드를 독립형 **composition function**으로 추출해야합니다. `useUserRepositories`를 생성하는 것부터 시작해봅시다: + +```js +// src/composables/useUserRepositories.js + +import { fetchUserRepositories } from '@/api/repositories' +import { ref, onMounted, watch, toRefs } from 'vue' + +export default function useUserRepositories(user) { + const repositories = ref([]) + const getUserRepositories = async () => { + repositories.value = await fetchUserRepositories(user.value) + } + + onMounted(getUserRepositories) + watch(user, getUserRepositories) + + return { + repositories, + getUserRepositories + } +} +``` + +그리고 검색 기능: + +```js +// src/composables/useRepositoryNameSearch.js + +import { ref, onMounted, watch, toRefs } from 'vue' + +export default function useRepositoryNameSearch(repositories) { + const searchQuery = ref('') + const repositoriesMatchingSearchQuery = computed(() => { + return repositories.value.filter(repository => { + return repository.name.includes(searchQuery.value) + }) + }) + + return { + searchQuery, + repositoriesMatchingSearchQuery + } +} +``` + +**이제 이 2가지 기능을 별도의 파일로 만들면, 컴포넌트에서 사용할 수 있습니다. 이 작업을 수행하는 방법은 다음과 같습니다:** + +```js +// src/components/UserRepositories.vue +import useUserRepositories from '@/composables/useUserRepositories' +import useRepositoryNameSearch from '@/composables/useRepositoryNameSearch' +import { toRefs } from 'vue' + +export default { + components: { RepositoriesFilters, RepositoriesSortBy, RepositoriesList }, + props: { + user: { type: String } + }, + setup (props) { + const { user } = toRefs(props) + + const { repositories, getUserRepositories } = useUserRepositories(user) + + const { + searchQuery, + repositoriesMatchingSearchQuery + } = useRepositoryNameSearch(repositories) + + return { + // 필터링되지 않은 repositories는 실제로 신경쓰지 않기 때문에 + // `repositories`이름으로 필터링된 결과를 노출시킬 수 있습니다 + repositories: repositoriesMatchingSearchQuery, + getUserRepositories, + searchQuery, + } + }, + data () { + return { + filters: { ... }, // 3 + } + }, + computed: { + filteredRepositories () { ... }, // 3 + }, + methods: { + updateFilters () { ... }, // 3 + } +} +``` + +이 시점에서 이미 무엇을 해야할지 알고 있으므로, 끝으로 건너뛰고 남은 필터링 기능을 마이그레이션하겠습니다. 이 가이드의 핵심이 아니기때문에, 구현의 세부사항은 얻을 필요는 없습니다. + +```js +// src/components/UserRepositories.vue +import { toRefs } from 'vue' +import useUserRepositories from '@/composables/useUserRepositories' +import useRepositoryNameSearch from '@/composables/useRepositoryNameSearch' +import useRepositoryFilters from '@/composables/useRepositoryFilters' + +export default { + components: { RepositoriesFilters, RepositoriesSortBy, RepositoriesList }, + props: { + user: { type: String } + }, + setup(props) { + const { user } = toRefs(props) + + const { repositories, getUserRepositories } = useUserRepositories(user) + + const { + searchQuery, + repositoriesMatchingSearchQuery + } = useRepositoryNameSearch(repositories) + + const { + filters, + updateFilters, + filteredRepositories + } = useRepositoryFilters(repositoriesMatchingSearchQuery) + + return { + // 필터링되지 않은 repositories는 실제로 신경쓰지 않기 때문에 + // `repositories`이름으로 필터링된 결과를 노출시킬 수 있습니다 + repositories: filteredRepositories, + getUserRepositories, + searchQuery, + filters, + updateFilters + } + } +} +``` + +이제 끝났습니다! + +여기서는 Composition API의 겉핥기만 했을뿐이며, 이를 통해 무엇을 할 수 있는지를 기억하세요. 자세한 내용은 설명서를 참조하세요.
([참고링크] https://composition-api.vuejs.org/) From 379b39d0de807c650dfc6b5b8c7a49ea77cecb26 Mon Sep 17 00:00:00 2001 From: kdeun1 Date: Fri, 7 Aug 2020 07:21:20 +0000 Subject: [PATCH 007/416] Translate instance.md via GitLocalize --- ko-KR/src/guide/instance.md | 149 ++++++++++++++++++++++++++++++++++++ 1 file changed, 149 insertions(+) create mode 100644 ko-KR/src/guide/instance.md diff --git a/ko-KR/src/guide/instance.md b/ko-KR/src/guide/instance.md new file mode 100644 index 000000000..6af0f4333 --- /dev/null +++ b/ko-KR/src/guide/instance.md @@ -0,0 +1,149 @@ +# 어플리케이션 인스턴스 + +## 인스턴스 생성하기 + +모든 Vue 어플리케이션은 `createApp` 함수를 사용하여 새로운 **어플리케이션 인스턴스**를 생성하여 시작합니다 : + +```js +Vue.createApp(/* 옵션들 */) +``` + +인스턴스가 생성되면, `mount` 메소드에 컨테이너를 전달하여 *mount* 할 수 있습니다. 예를들어, `
`에 Vue 어플리케이션을 마운트 시키고 싶다면, `#app`을 전달해야합니다: + +```js +Vue.createApp(/* 옵션들 */).mount('#app') +``` + +[MVVM 패턴](https://en.wikipedia.org/wiki/Model_View_ViewModel)과 밀접하게 관련있지는 않지만, Vue의 디자인은 MVVM 패턴에 의해 부분적으로 영감을 받았습니다. 종종 인스턴스를 참조하기 위해서 변수 `vm` (ViewModel의 줄임말)를 종종 사용합니다 . + +인스턴스를 생성할 때, **options 객체**를 전달합니다. 이 가이드의 대부분은 원하는 동작을 만드는 이러한 옵션들을 사용할 수 있는 방법에 대해 기술합니다. 참고로, [API 레퍼런스](../api/options-data.html)에서 전체 옵션 목록을 찾아볼 수 있습니다. + +Vue 어플리케이션은 `createApp`으로 생성되며, 필요에 따라 중첩될 수 있고 재사용가능한 컴포넌트로 구성된 **root instance**로 구성됩니다. 예를 들어, `todo` 앱의 컴포넌트 트리는 다음과 같습니다: + +``` +Root Instance +└─ TodoList + ├─ TodoItem + │ ├─ DeleteTodoButton + │ └─ EditTodoButton + └─ TodoListFooter + ├─ ClearTodosButton + └─ TodoListStatistics +``` + +[컴포넌트 시스템](component-basics.html)에 대해서는 나중에 자세히 설명하겠습니다. 지금은 모든 Vue 컴포넌트들도 또한 인스턴스이므로 동일한 옵션 객체를 허용합니다. + +## 데이터와 메소드 + +인스턴스가 생성될 때, `data`에서 발견된 모든 속성들을 [Vue의 **반응성 시스템**](reactivity.html)에 추가합니다. 이 속성의 값들이 변하는 경우, 화면이 "반응"하고 새 값과 일치하도록 갱신됩니다. + +```js +// data 객체 +const data = { a: 1 } + +// 객체가 루트 인스턴스에 추가됩니다 +const vm = Vue.createApp({ + data() { + return data + } +}).mount('#app') + +// 인스턴스에서 속성을 가져오면 +// 원래 데이터에서 속성을 반환합니다 +vm.a === data.a // => true + +// 인스턴스에서 속성을 설정하면 +// 원래 데이터에도 영향을 미칩니다 +vm.a = 2 +data.a // => 2 +``` + +데이터가 변경되면, 화면은 다시 렌더링됩니다. 인스턴스 생성 시 `data`의 속성이 존재하는 경우에만 **반응**한다는 점에 유의해야합니다. 즉, 다음과 같이 새로운 속성을 추가하는 경우에는: + +```js +vm.b = 'hi' +``` + +`b`가 변경되어도 화면이 갱신되지 않습니다. 나중에 속성이 필요로 하지만, 빈 값이거나 존재하지 않은 상태로 시작한다면 아래와 같이 초기 값을 지정할 필요가 있습니다: + +```js +data() { + return { + newTodoText: '', + visitCount: 0, + hideCompletedTodos: false, + todos: [], + error: null + } +} +``` + +여기서 유일한 예외는 `Object.freeze()`를 사용하는 경우입니다. 이는 기존 속성이 변경되는 것을 막아 반응성 시스템이 변경사항을 *추적*할 수 없다는 것을 의미합니다. + +```js +const obj = { + foo: 'bar' +} + +Object.freeze(obj) + +const vm = Vue.createApp({ + data() { + return obj + } +}).mount('#app') +``` + +```html +
+

{{ foo }}

+ + +
+``` + +Vue 인스턴스는 데이터 속성 이외에도 여러가지 유용한 인스턴스 속성 및 메소드를 제공합니다. 다른 사용자 정의 속성과 구분하기 위해 `$` 접두어를 붙였습니다. 예: + +```js +const vm = Vue.createApp({ + data() { + return { + a: 1 + } + } +}).mount('#example') + +vm.$data.a // => 1 +``` + +나중에 [API reference](../api/instance-properties.html)에서 인스턴스 속성 및 메소드의 전체 목록을 확인하세요. + +## 인스턴스 라이프사이클 훅 + +각 Vue 인스턴스는 생성될 때, 일련의 초기화 단계를 거칩니다. 예를들어, 데이터 관찰을 설정하는 경우, 템플릿을 컴파일하는 경우, DOM에 인스턴스를 마운트하는 경우, 그리고 데이터가 변경되어 DOM을 업데이트하는 경우가 있습니다. 그 과정에서 **라이프사이클 훅**이라고 불리우는 기능을 실행하여 특정 단계에서 사용자 고유의 코드를 추가할 수 있는 기회를 제공합니다. + +예를들어, [created](../api/options-lifecycle-hooks.html#created) 훅은 인스턴스가 생성된 후에 코드를 실행하는데 사용됩니다: + +```js +Vue.createApp({ + data() { + return { + a: 1 + } + }, + created() { + // `this`는 vm instance을 가리킵니다 + console.log('a is: ' + this.a) // => "a is: 1" + } +}) +``` + +인스턴스 라이프사이클에는 [mounted](../api/options-lifecycle-hooks.html#mounted), [updated](../api/options-lifecycle-hooks.html#updated), [unmounted](../api/options-lifecycle-hooks.html#unmounted) 과 같은 다른 훅도 존재합니다. 모든 라이프사이클 훅에서는 Vue인스턴스를 가리키는 `this` 컨텍스트와 함께 호출됩니다. + +::: tip options 속성이나 콜백에서 `created: () => console.log(this.a)`이나 `vm.$watch('a', newValue => this.myMethod())` 과 같은 [화살표 함수](https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Functions/Arrow_functions)를 사용하지 마세요. 화살표함수는 `this`가 없기 때문에, `this`는 다른 변수로 취급되거나 호출한 변수를 발견할 때까지 부모 스코프에서 해당 변수를 찾을것입니다. 이 때문에 `Uncaught TypeError: Cannot read property of undefined` 또는
`Uncaught TypeError: this.myMethod is not a function`와 같은 오류가 발생하게 됩니다. ::: + +## 라이프사이클 다이어그램 + +아래는 인스턴스 라이프사이클에 대한 다이어그램입니다. 지금 당장 모든 것을 완전히 이해할 필요는 없지만 다이어그램은 앞으로 도움이 될 것입니다. + +Instance lifecycle hooks From b182272d7ef578c9a51b76de480dff840f1796f4 Mon Sep 17 00:00:00 2001 From: Yunsup Sim Date: Fri, 7 Aug 2020 07:21:44 +0000 Subject: [PATCH 008/416] Translate mixins.md via GitLocalize --- ko-KR/src/guide/mixins.md | 222 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 222 insertions(+) create mode 100644 ko-KR/src/guide/mixins.md diff --git a/ko-KR/src/guide/mixins.md b/ko-KR/src/guide/mixins.md new file mode 100644 index 000000000..0fc0ae6d8 --- /dev/null +++ b/ko-KR/src/guide/mixins.md @@ -0,0 +1,222 @@ +# 믹스인 + +## 기초 + +믹스인(mixin)은 Vue 컴포넌트에 재사용 가능한 기능을 갖게 하는 유연한 방법입니다. 믹스인 객체는 모든 컴포넌트 옵션을 포함할 수 있습니다. 컴포넌트가 믹스인을 사용하면, 해당 믹스인의 모든 옵션이 컴포넌트 자체의 옵션으로 "혼합"됩니다. + +예시: + +```js +// mixin 객체 정의 +const myMixin = { + created() { + this.hello() + }, + methods: { + hello() { + console.log('hello from mixin!') + } + } +} + +// mixin을 사용할 어플리케이션 정의 +const app = Vue.createApp({ + mixins: [myMixin] +}) + +app.mount('#mixins-basic') // => "hello from mixin!" +``` + +## 옵션 병합 + +믹스인과 컴포넌트 자신은 중복되는 옵션을 가지고 있는 경우에는 적절한 방법을 사용해서 "병합"됩니다. + +예를 들어 data 객체가 충돌하는 경우에는 컴포넌트의 data 객체가 우선순위를 갖으면서 재귀적으로 병합됩니다. + +```js +const myMixin = { + data() { + return { + message: 'hello', + foo: 'abc' + } + } +} + +const app = Vue.createApp({ + mixins: [myMixin], + data() { + return { + message: 'goodbye', + bar: 'def' + } + }, + created() { + console.log(this.$data) // => { message: "goodbye", foo: "abc", bar: "def" } + } +}) +``` + +같은 이름의 훅 함수는 모두 호출될 수 있게 배열에 병합됩니다. 믹스인 훅은 컴포넌트 자체의 훅이 호출되기 **전에** 호출됩니다. + +```js +const myMixin = { + created() { + console.log('mixin hook called') + } +} + +const app = Vue.createApp({ + mixins: [myMixin], + created() { + console.log('component hook called') + } +}) + +// => "mixin hook called" +// => "component hook called" +``` + +`methods`, `components`, `directives`같은 객체 값을 요구하는 옵션은 같은 객체에 병합됩니다. 이러한 객체에 충돌하는 키가 있을 경우에는 컴포넌트의 옵션이 우선순위를 갖습니다. + +```js +const myMixin = { + methods: { + foo() { + console.log('foo') + }, + conflicting() { + console.log('from mixin') + } + } +} + +const app = Vue.createApp({ + mixins: [myMixin], + methods: { + bar() { + console.log('bar') + }, + conflicting() { + console.log('from self') + } + } +}) + +const vm = app.mount('#mixins-basic') + +vm.foo() // => "foo" +vm.bar() // => "bar" +vm.conflicting() // => "from self" +``` + +## 전역 믹스인 + +믹스인을 Vue 어플리케이션에 전역으로 적용할 수도 있습니다. + +```js +const app = Vue.createApp({ + myOption: 'hello!' +}) + +// `myOption` 사용자 정의 옵션을 위한 핸들러 주입 +app.mixin({ + created() { + const myOption = this.$options.myOption + if (myOption) { + console.log(myOption) + } + } +}) + +app.mount('#mixins-global') // => "hello!" +``` + +사용에 주의하세요! 믹스인을 전역으로 적용하면, 이후에 해당 어플리케이션에서 만드는 자식 컴포넌트와 같은 **모든** 컴포넌트 인스턴스에 영향을 끼칩니다. + +```js +const app = Vue.createApp({ + myOption: 'hello!' +}) + +// `myOption` 사용자 정의 옵션을 위한 핸들러 주입 +app.mixin({ + created() { + const myOption = this.$options.myOption + if (myOption) { + console.log(myOption) + } + } +}) + +// `myOption`을 자식 컴포넌트에도 삽입 +app.component('test-component', { + myOption: 'hello from component!' +}) + +app.mount('#mixins-global') + +// => "hello!" +// => "hello from component!" +``` + +대부분의 경우에는 위 예제같이 사용자 정의 옵션 병합 방법에만 이용하는 게 좋습니다. 중복 적용을 피하기 위해 [플러그인](plugins.html)으로 제공하는 것도 좋은 방법입니다. + +## 사용자 정의 옵션 병합 방법 + +사용자 정의 옵션이 병합될 때 기존 값을 덮어쓰는 기본 방법을 사용합니다. 사용자 정의 로직을 사용해 사용자 정의 옵션을 병합하려면, `app.config.optionMergeStrategies`에 함수에 추가해야 합니다. + +```js +const app = Vue.createApp({}) + +app.config.optionMergeStrategies.customOption = (toVal, fromVal) => { + // return 병합된 값 +} +``` + +해당 함수는 첫 번째와 두 번째 인자로 각각 부모와 자식 인스턴스에 정의한 옵션의 값을 전달받습니다. 믹스인을 사용할 때 매개변수에 무엇이 있는지 확인해보겠습니다. + +```js +const app = Vue.createApp({ + custom: 'hello!' +}) + +app.config.optionMergeStrategies.custom = (toVal, fromVal) => { + console.log(fromVal, toVal) + // => "goodbye!", undefined + // => "hello", "goodbye!" + return fromVal || toVal +} + +app.mixin({ + custom: 'goodbye!', + created() { + console.log(this.$options.custom) // => "hello!" + } +}) +``` + +보시다시피, 콘솔에는 먼저 믹스인에서 `toVal`와 `fromVal`이 출력되고 그 다음 `app`에서 출력됩니다. `fromVal`는 존재한다면 항상 반환되는데, 그래서 `this.$options.custom`가 마지막으로 `hello!`설정되는 것입니다. 이번에는 *항상 자식 인스턴스의 값을 반환*하는 방법으로 변경해봅시다. + +```js +const app = Vue.createApp({ + custom: 'hello!' +}) + +app.config.optionMergeStrategies.custom = (toVal, fromVal) => toVal || fromVal + +app.mixin({ + custom: 'goodbye!', + created() { + console.log(this.$options.custom) // => "goodbye!" + } +}) +``` + +Vue 2에서는 믹스인은 컴포넌트 로직을 재사용할 수 있게 만드는 주 도구였습니다. 하지만, 몇 가지 문제가 있었습니다. + +- 믹스인은 충돌이 잘 발생했습니다. 각 기능의 속성이 같은 컴포넌트에 병합되었기 때문에, 속성 이름 충돌을 피하고 디버깅을 하기 위해 다른 모든 기능에 대해 알아야 했습니다. + +- 재사용성이 제한됐었습니다. 논리를 변경하기 위해 매개 변수를 믹스 인에 전달할 수 없으므로 논리를 추상화할 때 유연성이 떨어졌습니다. + +이 문제를 해결하기 위해서 우리는 논리적인 우려를 바탕으로 코드를 정리하는 새로운 방법인 [Composition API](composition-api-introduction.html)를 추가했습니다. From c7beb3b86bbce584688faf0ff13bd6356499eff0 Mon Sep 17 00:00:00 2001 From: Sunghwan Shin Date: Mon, 10 Aug 2020 11:43:33 +0000 Subject: [PATCH 009/416] Translate component-custom-events.md via GitLocalize --- ko-KR/src/guide/component-custom-events.md | 229 +++++++++++++++++++++ 1 file changed, 229 insertions(+) create mode 100644 ko-KR/src/guide/component-custom-events.md diff --git a/ko-KR/src/guide/component-custom-events.md b/ko-KR/src/guide/component-custom-events.md new file mode 100644 index 000000000..d970633a6 --- /dev/null +++ b/ko-KR/src/guide/component-custom-events.md @@ -0,0 +1,229 @@ +# 커스텀 이벤트 + +> 이 페이지는 여러분이 이미 [컴포넌트 기초](component-basics.md)를 읽었다고 가정하고 쓴 내용입니다. 컴포넌트가 처음이라면 기초 문서를 먼저 읽으시기 바랍니다. + +## 이벤트 이름 + +컴포넌트 및 props와는 달리, 이벤트는 자동 대소문자 변환을 제공하지 않습니다. emit할 이벤트의 이름은 자동 대소문자 변환을 사용하는 것 대신 정확한 이름을 사용하여야 합니다. 예를 들어, 아래와 같이 camelCase로 작성된 이벤트를 emit하는 경우: + +```js +this.$emit('myEvent') +``` + +아래와 같이 kebab-case로 이벤트를 청취하는 경우 아무런 일도 일어나지 않습니다: + +```html + + +``` + +컴포넌트 및 props와는 다르게 이벤트 이름은 자바스크립트 변수나 속성의 이름으로 사용되는 경우가 없으며, 따라서 camelCase나 PascalCase를 사용할 필요가 없습니다. 또한, (HTML이 대소문자를 구분하지 않는 특성 때문에) DOM 템플릿의 `v-on` 이벤트리스너는 항상 자동으로 소문자 변환되기 때문에 `@myEvent` 는 자동으로 `@myevent`로 변환됩니다. -- 즉, `myEvent` 이벤트를 들을 수 없습니다. + +이러한 이유 때문에, 이벤트 이름에는 ** 항상 kebab-case를 사용하는것**이 권장됩니다. + +## 커스텀 이벤트 정의하기 + +Emit된 이벤트는 컴포넌트 상에서 `emits` 옵션을 통해 정의될 수 있습니다. + +```js +app.component('custom-form', { + emits: ['in-focus', 'submit'] +}) +``` + +만약 `emits` 옵션을 이용해 네이티브 이벤트(e.g., `click`)가 재정의 된 경우, 컴포넌트에 정의된 커스텀 이벤트가 네이티브 이벤트를 덮어씁니다. + +::: 팁 - 컴포넌트가 어떻게 동작하는지를 좀더 잘 문서화하기 위해, 발생하는 모든 이벤트를 정의하는 것이 권장됩니다. ::: + +### Emit 된 이벤트 검사하기 + +prop 타입 검사와 비슷하게, emit된 이벤트 또한 배열 형식 대신 오브젝트 형식으로 선언함으로써 검사를 추가할 수 있습니다. + +검사를 추가하기 위해서는 `$emit`의 전달인자를 받아 이벤트가 유효한지를 검증하여 boolean을 반환하는 함수를 이벤트에 할당합니다. + +```js +app.component('custom-form', { + emits: { + // 검사 절차 없음 + click: null, + + // submit 이벤트 검사 + submit: ({ email, password }) => { + if (email && password) { + return true + } else { + console.warn('잘못된 이벤트 페이로드입니다!') + return false + } + } + }, + methods: { + submitForm() { + this.$emit('submit', { email, password }) + } + } +}) +``` + +## `v-model` 인자 + +기본적으로 컴포넌트 상의 `v-model`는 `modelValue`를 props처럼, `update:modelValue`를 이벤트처럼 사용합니다.
이 때, `v-model`에 전달인자를 넘겨줌으로써 이 이름(modalValue)을 변경할 수 있습니다: + +```html + +``` + +이 경우, 자식 컴포넌트는 `foo`를 prop으로, 동기화 이벤트에 대해서는 `update:foo`를 emit하도록 상정합니다: + +```js +const app = Vue.createApp({}) + +app.component('my-component', { + props: { + foo: String + }, + template: ` + + ` +}) +``` + +```html + +``` + +## 다중 `v-model` 바인딩 + +[`v-model` arguments](#v-model-arguments) 단락에서 다루었던 개별 prop과 이벤트를 타겟하는 능력을 극대화하기 위해, 단일 컴포넌트 인스턴스에 대해 다중 v-model 바인딩을 만들 수 있습니다. + +각 v-model은 추가 컴포넌트 옵션 없이도 다른 prop을 동기화합니다: + +```html + +``` + +```js +const app = Vue.createApp({}) + +app.component('user-name', { + props: { + firstName: String, + lastName: String + }, + template: ` + + + + ` +}) +``` + +

아래 Pen을 참고하세요. Multiple v-models by Vue (@Vue) on CodePen.

+ +## `v-model` 수식어 핸들링 + +폼 인풋 바인딩에서 보았던 것 처럼, `v-model`은
`.trim`, `.number`, `.lazy` 등의 [빌트인 수식어](/guide/forms.html#modifiers) 를 가지고 있습니다. 상황에 따라서 이러한 커스텀 수식어를 만들어 추가하는 것이 가능합니다. + +예제로써, `v-model` 바인딩을 통해 전달된 문자열의 첫 글자를 대문자로 바꾸는 `capitalize`, 수식어를 만들어 봅시다. + +컴포넌트의 `v-model`에 추가된 수식어는 `modelModifiers` prop을 통해 컴포넌트에 전달됩니다. 아래 예제에서는 빈 오브젝트를 기본값으로 설정하는 `modelModifiers` prop을 갖는 컴포넌트를 만들었습니다. + +컴포넌트의 `created` 라이프사이클 훅이 호출되었을 때 --`v-model` 바인딩이 `v-model.capitalize="bar"`와 같이 선언되었기 때문에 -- `modelModifiers` prop이 `capitalize`를 포함하며 그 값이 `true`라는 것을 알아두세요. + +```html + +``` + +```js +app.component('my-component', { + props: { + modelValue: String, + modelModifiers: { + default: () => ({}) + } + }, + template: ` + + `, + created() { + console.log(this.modelModifiers) // { capitalize: true } + } +}) +``` + +이제 우리의 prop이 셋업되었으며, `modelModifiers` 오브젝트의 키를 확인하고 emit된 값을 변경하기 위한 핸들러를 작성할 수 있습니다. 아래 예제는 `` 엘리먼트가 `input` 이벤트를 발생시켰을 때 문자열을 대문자로 바꿉니다. + +```html +
+ + {{ myText }} +
+``` + +```js +const app = Vue.createApp({ + data() { + return { + myText: '' + } + } +}) + +app.component('my-component', { + props: { + modelValue: String, + modelModifiers: { + default: () => ({}) + } + }, + methods: { + emitValue(e) { + let value = e.target.value + if (this.modelModifiers.capitalize) { + value = value.charAt(0).toUpperCase() + value.slice(1) + } + this.$emit('update:modelValue', value) + } + }, + template: `` +}) + +app.mount('#app') +``` + +`v-model`에 전달인자를 바인딩하기 위해서, prop의 이름을 `arg + "Modifiers"` 형태로 작성하여야 합니다: + +```html + +``` + +```js +app.component('my-component', { + props: ['foo', 'fooModifiers'], + template: ` + + `, + created() { + console.log(this.fooModifiers) // { capitalize: true } + } +}) +``` From fec610d7f339559d1a29b8ca0bd62bbbcbf32f2c Mon Sep 17 00:00:00 2001 From: zero86 Date: Mon, 10 Aug 2020 12:15:19 +0000 Subject: [PATCH 010/416] Translate application-api.md via GitLocalize --- ko-KR/src/api/application-api.md | 237 +++++++++++++++++++++++++++++++ 1 file changed, 237 insertions(+) create mode 100644 ko-KR/src/api/application-api.md diff --git a/ko-KR/src/api/application-api.md b/ko-KR/src/api/application-api.md new file mode 100644 index 000000000..722e3a25b --- /dev/null +++ b/ko-KR/src/api/application-api.md @@ -0,0 +1,237 @@ +# 애플리케이션 API + +Vue 3에서는 Vue의 동작을 전역적으로 변이시키는 API는 이제 새로운 `createApp` 메서드로 생성된 애플리케이션 인스턴스로 옮겨졌습니다. 또한 그 영향은 이제 해당 특정 애플리케이션의 인스턴스로 범위가 지정됩니다. + +```js +import { createApp } from 'vue' + +const app = createApp({}) +``` + +`createApp`을 호출하면 애플리케이션 인스턴스를 반환합니다. 이 인스턴스는 애플리케이션 컨텍스트를 제공합니다. 애플리케이션 인스턴스에 의해 마운트 된 전체 컴포넌트 트리는 Vue 2.x에서 이전에 "글로벌"이었던 구성을 제공하는 동일한 컨텍스트를 공유합니다. + +또한 `createApp` 메서드는 애플리케이션 인스턴스 자체를 반환하므로, 다음 섹션에서 확인할 수 있는 이후에 다른 메서드를 연결할 수 있습니다. + +## component + +- **전달인자:** + + - `{string} name` + - `{Function | Object} [definition]` + +- **사용방법:** + + 전역 컴포넌트를 등록하거나 검색합니다. 주어진 `name` 매개 변수로 컴포넌트의 `name`을 자동으로 설정합니다. + +- **예시:** + +```js +import { createApp } from 'vue' + +const app = createApp({}) + +// register an options object +app.component('my-component', { + /* ... */ +}) + +// retrieve a registered component (always return constructor) +const MyComponent = app.component('my-component', {}) +``` + +- **참고:** + [Components](../guide/component-basics.html) + +## config + +- **사용방법:** + +애플리케이션 구성을 포함하는 객체. + +- **예시:** + +```js +import { createApp } from 'vue' +const app = createApp({}) + +app.config = {...} +``` + +- **참고:** + [Application Config](./application-config.html) + +## directive + +- **전달인자:** + + - `{string} name` + - `{Function | Object} [definition]` + +- **사용방법:** + + 전역 디렉티브를 등록하거나 검색합니다. + +- **예시:** + +```js +import { createApp } from 'vue' +const app = createApp({}) + +// register +app.directive('my-directive', { + // Directive has a set of lifecycle hooks: + // called before bound element's parent component is mounted + beforeMount() {}, + // called when bound element's parent component is mounted + mounted() {}, + // called before the containing component's VNode is updated + beforeUpdate() {}, + // called after the containing component's VNode and the VNodes of its children // have updated + updated() {}, + // called before the bound element's parent component is unmounted + beforeUnmount() {}, + // called when the bound element's parent component is unmounted + unmounted() {} +}) + +// register (function directive) +app.directive('my-directive', () => { + // this will be called as `mounted` and `updated` +}) + +// getter, return the directive definition if registered +const myDirective = app.directive('my-directive') +``` + +디렉티브 hooks 에는 다음과 같은 인자들이 전달됩니다. + +#### el + +디렉티브에 바인딩 된 엘리먼트를 나타냅니다. 이 엘리먼트를 이용하여 DOM을 직접 조작하는 데 사용할 수 있습니다. + +#### binding + +바인딩 객체는 다음과 같은 속성을 포함하고 있습니다. + +- `instance`: 디렉티브가 사용되는 컴포넌트의 인스턴스 +- `value`: 디렉티브에 전달된 값. 예를 들어 `v-my-directive="1 + 1"` 에서 전달된 값은 `2` 가 됩니다. +- `oldValue`: 이전 값이며, `beforeUpdate` 와 `updated` 에서만 사용이 가능합니다. 값 변경에 관계없이 사용할 수 있습니다. +- `arg`: 디렉티브에 전달된 인자. 예를 들어 `v-my-directive:foo` 에서 전달된 인자는 `"foo"` 가 됩니다. +- `modifiers`: 수식어를 포함하는 객체. 예를 들어 `v-my-directive.foo.bar` 에서 수식어 객체는 `{ foo: true, bar: true }` 가 됩니다. +- `dir`: 디렉티브가 등록 될 때 매개 변수로 전달되는 객체. 예를 들어, 아래 디렉티브에서 + +```js +app.directive('focus', { + mounted(el) { + el.focus() + } +}) +``` + +`dir` 객체는 다음과 같습니다: + +```js +{ + mounted(el) { + el.focus() + } +} +``` + +#### vnode + +위의 el 인자로 받은 실제 DOM 엘리먼트의 청사진 입니다.
vnode 는 가상 DOM 노드를 의미합니다. + +#### prevNode + +이전 가상 노드 입니다. `beforeUpdate` 와 `updated` hook 에서만 사용할 수 있습니다. + +::: tip `el` 인자와는 별도로, 이러한 인자들은 읽기전용이므로 절대 수정하지 마세요. 만약 hooks 간에 정보를 공유해야 한다면, 엘리먼트의 [dataset](https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement/dataset) 을 이용하여 공유하는 것이 좋습니다. ::: + +- **참고:** + [Custom Directives](../guide/custom-directive.html) + +## mixin + +- **전달인자:** + + - `{Object} mixin` + +- **사용방법:** + + 애플리케이션 전역에 믹스인을 등록합니다. 일단 등록되면 믹스인은 현재 어플리케이션 내 모든 컴포넌트 템플릿에서 사용할 수 있습니다. 이것은 플러그인 작성자가 컴포넌트에 사용자 정의 기능을 주입하는 데 사용할 수 있습니다. **애플리케이션 코드에서 권장되지 않음**. + +- [Global Mixin](../guide/mixins.html#global-mixin) + +## mount + +- **전달인자:** + + - `{Element | string} rootContainer` + - `{boolean} isHydrate` + +- **사용방법:** + + 제공된 DOM 엘리먼트에 애플리케이션 인스턴스의 루트 컴포넌트를 마운트합니다. + +- **예시:** + +```html + +
+ +``` + +```js +import { createApp } from 'vue' + +const app = createApp({}) +// do some necessary preparations +app.mount('#my-app') +``` + +- **참고:** + - [Lifecycle Diagram](../guide/instance.html#lifecycle-diagram) + +## unmount + +- **전달인자:** + + - `{Element | string} rootContainer` + +- **사용방법:** + + 제공된 DOM 엘리먼트에서 애플리케이션 인스턴스의 루트 컴포넌트를 마운트 해제합니다. + +- **예시:** + +```html + +
+ +``` + +```js +import { createApp } from 'vue' + +const app = createApp({}) +// do some necessary preparations +app.mount('#my-app') + +// Application will be unmounted 5 seconds after mount +setTimeout(() => app.unmount('#my-app'), 5000) +``` + +## use + +- **전달인자:** + + - `{Object | Function} plugin` + +- **사용방법:** + + Vue.js 플러그인을 설치하세요. 플러그인이 객체인 경우에는 `install` 메서드를 노출해야합니다. 함수인 경우, install 메서드로 처리됩니다. install 메서드는 Vue 를 인자로 사용하여 호출됩니다. + + 동일한 플러그인에서 이 메서드를 여러 번 호출하면 플러그인이 한 번만 설치됩니다. + +- [Plugins](../guide/plugins.html) From c26436c3fe98ca52ba513d0f21b6c87ddc7f8614 Mon Sep 17 00:00:00 2001 From: kdeun1 Date: Mon, 10 Aug 2020 12:17:15 +0000 Subject: [PATCH 011/416] Translate composition-api-provide-inject.md via GitLocalize --- .../guide/composition-api-provide-inject.md | 120 ++++++++++++++++++ 1 file changed, 120 insertions(+) create mode 100644 ko-KR/src/guide/composition-api-provide-inject.md diff --git a/ko-KR/src/guide/composition-api-provide-inject.md b/ko-KR/src/guide/composition-api-provide-inject.md new file mode 100644 index 000000000..1d1fd3fc9 --- /dev/null +++ b/ko-KR/src/guide/composition-api-provide-inject.md @@ -0,0 +1,120 @@ +# Provide / Inject + +> 이 가이드는 [Composition API Introduction](composition-api-introduction.html) 와 [Reactivity Fundamentals](reactivity-fundamentals.html)를 이미 읽었다고 가정합니다. Composition API를 처음 사용하는 경우 먼저 읽어보세요. + +Composition API와 함께 [provide / inject](component-provide-inject.html)를 사용할 수 있습니다. provide / inject는 현재 활성화된 인스턴스의 [`setup()`](composition-api-setup.html) 중에 호출 될 수 있습니다. + +예를들어, 최상위 컴포넌트에 book name을 provide하고, 하위 컴포넌트에 inject하려는 경우: + +```js +import { provide, inject } from 'vue' + +const RootComponent = { + setup() { + provide('book', 'Vue 3 guide') + } +} + +const MyBook = { + setup() { + const book = inject( + 'book', + 'Eloquent Javascript' /* 선택적 기본 값 */ + ) + return { + book + } + } +} +``` + +`inject`은 두번째 전달인자로서 선택적 기본 값을 허용합니다. 기본 값이 제공되지 않고 provide 컨텍스트에서 속성을 찾을 수 없는 경우, `inject`은 `undefined`를 반환합니다. + +여러 값을 provide 또는 inject 하는 경우, 각각의 `provide` 나 `inject` 을 호출하여 수행할 수 있습니다: + +```js{5-6,12-16} +import { provide, inject } from 'vue' + +const RootComponent = { + setup() { + provide('book', 'Vue 3 guide') + provide('year', '2020') + } +} + +const MyBook = { + setup() { + const book = inject( + 'book', + 'Eloquent Javascript' /* 선택적 기본 값 */ + ) + const year = inject('year') + + return { + book, + year + } + } +} +``` + +## 반응성 주입 + +provide된 값과 inject된 값 사이의 반응성을 유지하기 위해서, 값을 provide 할 때 [ref](reactivity-fundamentals.html#creating-standalone-reactive-values-as-refs)나 [reactive](reactivity-fundamentals.html#declaring-reactive-state)를 사용할 수 있습니다: + +```js +import { ref, reactive } from 'vue' + +// in provider +setup() { + const book = reactive({ + title: 'Vue 3 Guide', + author: 'Vue Team' + }) + const year = ref('2020') + + provide('book', book) + provide('year', year) +} + +// in consumer +setup() { + const book = inject('book') + const year = inject('year') + + return { book, year } +} +``` + +이제, *provider* 컴포넌트에서 `book` 이나 `year` 가 변경되면, inject하는 컴포넌트에서 변경사항을 감지할 수 있습니다. + +::: warning injected된 반응형 속성을 변경하는 것은 Vue의 단방향 데이터 흐름을 깨기 때문에 추천하지 않습니다. 대신, *provide된* 값을 변경하거나 변경하는 메소드를 provide하세요. + +```js +import { ref, reactive } from 'vue' + +// in provider +setup() { + const book = reactive({ + title: 'Vue 3 Guide', + author: 'Vue Team' + }) + + function changeBookName() { + book.title = 'Vue 3 Advanced Guide' + } + + provide('book', book) + provide('changeBookName', changeBookName) +} + +// in consumer +setup() { + const book = inject('book') + const changeBookName = inject('changeBookName') + + return { book, changeBookName } +} +``` + +::: From 5f8a665382f599837a59c60cd87267666b338964 Mon Sep 17 00:00:00 2001 From: Terrorboy Date: Mon, 10 Aug 2020 12:20:35 +0000 Subject: [PATCH 012/416] Translate installation.md via GitLocalize --- ko-KR/src/guide/installation.md | 147 ++++++++++++++++++++++++++++++++ 1 file changed, 147 insertions(+) create mode 100644 ko-KR/src/guide/installation.md diff --git a/ko-KR/src/guide/installation.md b/ko-KR/src/guide/installation.md new file mode 100644 index 000000000..a1db164bb --- /dev/null +++ b/ko-KR/src/guide/installation.md @@ -0,0 +1,147 @@ +# 설치방법 + +## 릴리즈 노트 + +최신 베타 버전: 3.0.0-rc.5 + +각 버전에 대한 자세한 릴리즈 정보는 [GitHub](https://github.com/vuejs/vue-next/releases)에서 보실 수 있습니다. + +## Vue Devtools + +> 현재 베타 버전 + +> Vue 3 용 Vue Devtools를 사용하기 위해서는 최소 `vue@^3.0.0-rc.1`이 필요합니다. + +Vue를 사용할 때, 브라우저에 [Vue Devtools](https://github.com/vuejs/vue-devtools#vue-devtools) 를 설치 하는것이 좋습니다. Vue 앱을 보다 사용자 친화적인 인터페이스에서 검사하고 디버깅할 수 있습니다. + +[크롬 확장 프로그램](https://chrome.google.com/webstore/detail/vuejs-devtools/ljjemllljcmogpfapbkkighbhhppjdbg) + +[파이어폭스 애드온](https://addons.mozilla.org/en-US/firefox/addon/vue-js-devtools/) + +[독립형 일렉트론 앱](https://github.com/vuejs/vue-devtools/blob/dev/packages/shell-electron/README.md) + +## CDN + +프로토 타이핑또는 학습 목적이라면, 아래 코드로 최신 버전을 사용할 수 있습니다. + +```html + +``` + +프로덕션 환경인 경우 새 버전에서 예상치 못한 오류를 방지하려면 특정 버전의 빌드 파일을 추가하는것을 추천합니다. + +## NPM + +Vue를 사용하여 대규모 애플리케이션을 구축할 때 NPM를 이용한 설치를 권장하고 있습니다. NPM은 [Webpack](https://webpack.js.org/) 또는 [Browserify](http://browserify.org/)와 같은 모듈 번들러와 잘 작동합니다. Vue는 [싱글 파일 컴포넌트](../guide/single-file-component.html)를 만들기 위한 도구도 제공합니다. + +```bash +# latest stable +$ npm install vue@next +``` + +## CLI + +Vue.js는 단일 페이지 애플리케이션를 빠르게 구축할 수 있는 [공식 CLI](https://github.com/vuejs/vue-cli)를 제공합니다. 최신 프론트엔드 워크 플로우를 위해 사전 구성된 빌드 설정을 제공합니다. 핫 리로드, 저장시 린트 체크 및 프로덕션 준비가 된 빌드로 시작하고 실행하는데 몇 분 밖에 걸리지 않습니다. 상세한 내용은 [Vue CLI 문서](https://cli.vuejs.org)에서 찾아보실 수 있습니다. + +::: tip CLI는 Node.js 및 관련 빌드 도구에 대한 사전 지식을 전제로 하고 있습니다. Vue 또는 프런트엔드 빌드 도구를 처음 사용하는 경우 CLI를 사용하기 전에 빌드 도구없이 가이드를 읽어 보시기 바랍니다. ::: + +Vue 3의 경우 `npm`에서`@vue/cli@next`로 제공되는 Vue CLI v4.5를 사용해야 합니다. 업그레이드하려면 최신 버전의 `@vue/cli`를 전역으로 다시 설치해야 합니다. + +```bash +yarn global add @vue/cli@next +# OR +npm install -g @vue/cli@next +``` + +그런 다음 프로젝트에서 입력하세요. + +```bash +vue upgrade --next +``` + +## Vite + +[Vite](https://github.com/vitejs/vite)는 네이티브 ES 모듈을 가져오는 방식으로 코드의 빠른 제공을 가능하게 하는 Web 개발 빌드 도구입니다. + +Vue 프로젝트에서 터미널에 다음 명령을 실행하여 Vite로 빠르게 설정할 수 있습니다. + +NPM: + +```bash +$ npm init vite-app +$ cd +$ npm install +$ npm run dev +``` + +Yarn: + +```bash +$ yarn create vite-app +$ cd +$ yarn +$ yarn dev +``` + +## 다른 빌드 방법 + +[NPM 패키지 `dist/` 디렉토리](https://cdn.jsdelivr.net/npm/vue@3.0.0-rc.1/dist/)에는 Vue.js의 다양한 빌드 방법이 있습니다. 사용 사례에 따라 어떤 `dist` 파일을 사용해야 하는지에 대한 설명입니다. + +### 번들러 없는 CDN + +#### `vue(.runtime).global(.prod).js`: + +- 브라우저에서 직접 사용하기 위하여 ` ``` -`inject`은 두번째 전달인자로서 선택적 기본 값을 허용합니다. 기본 값이 제공되지 않고 provide 컨텍스트에서 속성을 찾을 수 없는 경우, `inject`은 `undefined`를 반환합니다. - -여러 값을 provide 또는 inject 하는 경우, 각각의 `provide` 나 `inject` 을 호출하여 수행할 수 있습니다: - -```js{5-6,12-16} -import { provide, inject } from 'vue' - -const RootComponent = { - setup() { - provide('book', 'Vue 3 guide') - provide('year', '2020') - } +```vue + + +``` -const MyBook = { - setup() { - const book = inject( - 'book', - 'Eloquent Javascript' /* 선택적 기본 값 */ - ) - const year = inject('year') +## Provide 사용하기 - return { - book, - year - } - } -} -``` +`setup()` 안에서 `provide`를 사용할 때, `vue`에서 메소드를 명시적으로 import함으로서 시작합니다. 이를 통해 고유한 `provide` 호출로 각 속성을 정의할 수 있습니다. -## 반응성 주입 +`provide` 펑션은 2개의 전달인자를 통해 속성을 정의할 수 있습니다: + +1. 속성명 (`` 타입) +2. 속성값 provide된 값과 inject된 값 사이의 반응성을 유지하기 위해서, 값을 provide 할 때 [ref](reactivity-fundamentals.html#creating-standalone-reactive-values-as-refs)나 [reactive](reactivity-fundamentals.html#declaring-reactive-state)를 사용할 수 있습니다: -```js +```vue{7,14-20} import { ref, reactive } from 'vue' // in provider @@ -86,11 +76,18 @@ setup() { } ``` +## Inject 사용하기 + 이제, *provider* 컴포넌트에서 `book` 이나 `year` 가 변경되면, inject하는 컴포넌트에서 변경사항을 감지할 수 있습니다. ::: warning injected된 반응형 속성을 변경하는 것은 Vue의 단방향 데이터 흐름을 깨기 때문에 추천하지 않습니다. 대신, *provide된* 값을 변경하거나 변경하는 메소드를 provide하세요. -```js +1. inject할 속성명 +2. 기본값 (**선택사항**) + +MyMarker 컴포넌트를 사용하여, 다음과 같은 코드로 리펙토링을 할 수 있습니다: + +```vue{3,6-14} import { ref, reactive } from 'vue' // in provider @@ -117,4 +114,174 @@ setup() { } ``` -::: +## 반응성 + +### 반응성 추가 + +provide된 값과 inject된 값 사이에 반응성을 추가하기 위해, 값을 provide할 때 [ref](reactivity-fundamentals.html#creating-standalone-reactive-values-as-refs) 나 [reactive](reactivity-fundamentals.html#declaring-reactive-state) 를 사용할 수 있습니다. + +`MyMap` 컴포넌트를 사용하여 아래와 같이 코드를 업데이트할 수 있습니다: + +```vue{7,15-22} + + + + +``` + +이제, 두 속성 중 하나가 변경되면, `MyMarker` 컴포넌트는 자동으로 업데이트됩니다! + +### 반응성 속성 변경하기 + +반응성있는 provide / inject값을 사용하는 경우, **가능하면 *provider* 내부에 반응성있는 속성에 대한 변이를 유지하는 것이 좋습니다**. + +예를들면, 사용자의 위치를 변경해야하는 경우, 이상적으로 `MyMap` 컴포넌트 내에 이 작업을 수행합니다. + +```vue{28-32} + + + + +``` + +그러나, 데이터가 inject된 컴포넌트 내부의 데이터를 업데이트해야하는 경우가 있습니다. 이 시나리오에서는 반응형있는 속성을 변경하는 방법을 메소드를 제공하는 것이 좋습니다. + +```vue{21-23,27} + + + + +``` + +```vue{9,14} + + +``` + +마지막으로, `provide`를 통해 전달된 데이터가 inject된 컴포넌트에 의해 변경되지 않도록 하려면, provide 속성에 `readonly`를 사용하는 것이 좋습니다. + +```vue{7,25-26} + + + + +``` From ab720c675c3a3c25c0618a3613364308d729a4c2 Mon Sep 17 00:00:00 2001 From: Seongsil Yoo Date: Thu, 20 Aug 2020 00:50:36 +0000 Subject: [PATCH 016/416] Translate routing.md via GitLocalize --- ko-KR/src/guide/routing.md | 44 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 44 insertions(+) create mode 100644 ko-KR/src/guide/routing.md diff --git a/ko-KR/src/guide/routing.md b/ko-KR/src/guide/routing.md new file mode 100644 index 000000000..da9560540 --- /dev/null +++ b/ko-KR/src/guide/routing.md @@ -0,0 +1,44 @@ +# 라우팅 + +## 공식 라우터 + +대부분의 단일 페이지 애플리케이션의 경우, 공식적으로 지원되는 [vue-router 라이브러리](https://github.com/vuejs/vue-router)를 사용하는 것이 좋습니다. 자세한 내용은 vue-router의 [문서](https://router.vuejs.org/)를 참조하십시오. + +## 단순한 라우팅 시작하기 + +매우 단순한 라우팅만 필요하고 완전한 기능을 갖춘 라우터 라이브러리를 사용하지 않으려면 다음과 같이 페이지 수준 컴포넌트를 동적으로 렌더링하면 됩니다. + +```js +const NotFoundComponent = { template: '

Page not found

' } +const HomeComponent = { template: '

Home page

' } +const AboutComponent = { template: '

About page

' } + +const routes = { + '/': HomeComponent, + '/about': AboutComponent +} + +const SimpleRouter = { + data: () => ({ + currentRoute: window.location.pathname + }), + + computed: { + CurrentComponent() { + return routes[this.currentRoute] || NotFoundComponent + } + }, + + render() { + return Vue.h(this.CurrentComponent) + } +} + +Vue.createApp(SimpleRouter).mount('#app') +``` + +[History API](https://developer.mozilla.org/en-US/docs/Web/API/History_API/Working_with_the_History_API)와 결합하면 매우 기본적이면서도 완전한 기능을 갖춘 클라이언트측 라우터를 구축할 수 있습니다. 실제로 이를 확인하려면, [예제 앱](https://github.com/phanan/vue-3.0-simple-routing-example)을 확인하십시오. + +## 써드파티 라우터 목록 + +만약 [Page.js](https://github.com/visionmedia/page.js)나 [Director](https://github.com/flatiron/director)같은 써드파티 라우터를 사용하는 것을 선호한다면, 통합하는 것도 [쉽습니다](https://github.com/phanan/vue-3.0-simple-routing-example/compare/master...pagejs). Page.js를 사용한 [완벽한 예제](https://github.com/phanan/vue-3.0-simple-routing-example/tree/pagejs)를 소개합니다. From 3e4c9af580cfff763f2ea09f91fc17dd1322ce4f Mon Sep 17 00:00:00 2001 From: kdeun1 Date: Thu, 20 Aug 2020 00:55:15 +0000 Subject: [PATCH 017/416] Translate composition-api-template-refs.md via GitLocalize --- .../guide/composition-api-template-refs.md | 87 +++++++++++++++++++ 1 file changed, 87 insertions(+) create mode 100644 ko-KR/src/guide/composition-api-template-refs.md diff --git a/ko-KR/src/guide/composition-api-template-refs.md b/ko-KR/src/guide/composition-api-template-refs.md new file mode 100644 index 000000000..122978f48 --- /dev/null +++ b/ko-KR/src/guide/composition-api-template-refs.md @@ -0,0 +1,87 @@ +## 템플릿 Refs + +> 이 섹션에서는 코드 예제에 [싱글파일 컴포넌트](single-file-component.html) 구문을 사용합니다. + +> 이 가이드에서는 사용자가 이미 [Composition API Introduction](composition-api-introduction.html)와 [Reactivity Fundamentals](reactivity-fundamentals.html)를 이미 읽었다고 가정합니다. Composition API를 처음 사용하는 경우 먼저 읽어보세요. + +Composition API를 사용할 때, [reactive refs API](reactivity-fundamentals.html#creating-standalone-reactive-values-as-refs)와 [template refs](component-template-refs.html)의 개념이 통합됩니다. 템플릿 내 요소 또는 컴포넌트 인스턴스에 대한 참조를 얻기 위해서, 평소와 같이 ref를 선언하고 [setup()](composition-api-setup.html)에서 반환할 수 있습니다: + +```html + + + +``` + +여기서 render context에 `root`를 노출하고 (root를) `ref="root"`를 통해 ref로 div에 바인딩합니다. 가상 DOM patch 알고리즘에서 VNode의 `ref` 키가 render context의 ref에 해당하면, VNode에 대응하는 요소나 컴포넌트 인스턴스는 해당 ref의 값에 할당됩니다. 이는 Virtual DOM mount / patch 과정 중에서 수행되므로, template refs는 초기 렌더링 이후에만 할당된 값을 받습니다. + +templates refs로 사용되는 refs는 다른 refs와 동일하게 작동합니다. 반응적이며 composition function으로 전달 또는 반환될 수 있습니다. + +### JSX와 함께 사용하기 + +```js +export default { + setup() { + const root = ref(null) + + return () => + h('div', { + ref: root + }) + + // with JSX + return () =>
+ } +} +``` + +### `v-for` 내부에서 사용하기 + +Composition API template refs는 `v-for` 내에서 사용될 때 특별한 처리를 하지 않습니다. 대신, function refs를 사용하여 커스텀 처리를 수행하세요: + +```html + + + +``` From 21824114d788348e209763be1cadf7a55f7370c3 Mon Sep 17 00:00:00 2001 From: Sunghwan Shin Date: Thu, 20 Aug 2020 00:57:56 +0000 Subject: [PATCH 018/416] Translate pull_request_template.md via GitLocalize --- ko-KR/.github/pull_request_template.md | 9 +++++++++ 1 file changed, 9 insertions(+) create mode 100644 ko-KR/.github/pull_request_template.md diff --git a/ko-KR/.github/pull_request_template.md b/ko-KR/.github/pull_request_template.md new file mode 100644 index 000000000..9b69030bf --- /dev/null +++ b/ko-KR/.github/pull_request_template.md @@ -0,0 +1,9 @@ +# ⚠️⚠️⚠️ 면책조항 ⚠️⚠️⚠️: + +PR을 날리는 것에 관심을 가져 주셔서 감사합니다! 현재 문서는 아직 베타버전이며, 팀은 변화의 한가운데에 있습니다. 이런 이유로 아직 저희는 **컨트리뷰터를 추가 할 준비가 되어 있지 않습니다.** + +## 어떻게 피드백을 전달할 수 있나요? + +저희가 여러분의 시간과 아이디어를 존중할 수 있도록 **풀 리퀘스트를 생성하는 대신 [이슈를 생성](https://github.com/vuejs/docs-next/issues/new)해 주세요.** 그렇지 않은 경우, 현재는 풀리퀘스트가 생성되더라도 곧바로 닫히게 됩니다. + +이해해 주셔서 감사합니다! From 545a1a35f7cf3183e1110b75dbaaf9435f84e4c8 Mon Sep 17 00:00:00 2001 From: OwenSong Date: Mon, 24 Aug 2020 13:01:22 +0000 Subject: [PATCH 019/416] Translate testing.md via GitLocalize --- ko-KR/src/guide/testing.md | 163 +++++++++++++++++++++++++++++++++++++ 1 file changed, 163 insertions(+) create mode 100644 ko-KR/src/guide/testing.md diff --git a/ko-KR/src/guide/testing.md b/ko-KR/src/guide/testing.md new file mode 100644 index 000000000..ce2e8e798 --- /dev/null +++ b/ko-KR/src/guide/testing.md @@ -0,0 +1,163 @@ +# 테스팅 + +## 소개 + +테스트는 신뢰할 수 있는 애플리케이션을 구축 하거나, 개인 또는 팀이 새로운 기능 빌드, 코드 리팩토링, 버그 수정 등의 작업에 중요한 역할을 할 수 있습니다. 테스팅에는 많은 의견들이 있지만, 웹 애플리케이션을 측면에서 종종 논의되는 세 가지 카테고리를 소개해드립니다. + +- 단위 테스팅 +- 컴포넌트 테스팅 +- 종단간 (E2E) 테스팅 + +이번 섹션은 테스팅의 생태계를 알아보고, Vue 애플리케이션 또는 컴포넌트 라이브러리를 위한 적절한 도구를 찾는 가이드를 제공합니다. + +## 단위 테스팅 + +### 소개 + +단위 테스트를 통해 코드 단위를 독립적으로 테스트 할 수 있습니다. 단위 테스팅은 개발자에게 코드에 대한 자신감을 줍니다. 철저하고 의미있는 테스트를 작성하면, 새로운 기능이 빌드되거나 코드를 리팩토링 할 때 애플리케이션이 기능적이고 안정적으로 유지 될 것이라는 확신을 할 수 있습니다. + +Vue 애플리케이션을 단위 테스트 하는 것은 다른 애플리케이션을 단위 테스트 하는 것과 크게 다르지 않습니다. + +### 프레임워크 선택 + +단위 테스팅에 대한 조언은 종종 프레임워크에 구애받지 않는(framwork-agnostic)경우가 많기 떄문에, 애플리케이션에 가장 적합한 단위 테스팅 도구인지 평가할 때 염두해야 할 몇 가지 기본 지침이 있습니다. + +#### 최고의 오류 보고 + +테스트에 실패 했을 때, 단위 테스팅 프레임워크는 유용한 에러 메세지를 제공하는 것이 중요합니다. 유용한 에러 메세지를 제공하는 기능은 assertion 라이브러리의 역할 입니다. 고품질의 오류 메시지가 포함 된 assertion 라이브러리는 디버깅 시간을 줄일 때 도움이 됩니다. 단순히 어떤 테스트가 실패했는지 알려주는 것 외에도, assertion 라이브러리는 테스트가 실패한 이유에 대한 컨텍스트를 제공합니다. (예 : 예상하는 것과 전달받은 것). + +Jest와 같은 단위 테스팅 프레임워크는 assertion 라이브러리를 포함합니다. 그와 다르게 Mocha등의 단위 테스팅 프레임워크의 경우 assertion 라이브러리를 별도로 설치해야합니다. (일반적으로 Chai 라이브러리) + +#### 활성화된 커뮤니티와 팀 + +대부분의 단위 테스팅 프레임워크는 오픈 소스이기 때문에 활발한 커뮤니티가 있는 것이 테스트와 프로젝트를 장기간 유지해야하는 일부 팀에게는 중요합니다. 또한 활발한 커뮤니티가 있다면 문제가 발생할 때마다 더 많은 도움을 받을 수 있는 이점이 있습니다. + +### 프레임워크 + +생태계에는 많은 도구들이 있지만, 다음은 Vue.js 생태계에서 사용되는 일반적인 단위 테스팅 도구들입니다. + +#### Jest + +Jest는 단순성에 초점을 맞춘 JavaScript 테스트 프레임워크입니다. 특징 중 하나는 애플리케이션의 단위를 확인하는 기능을 제공하기 위해 테스트의 스냅 샷을 찍습니다. + +**자료:** + +- Jest 공식 웹사이트 +- 공식 Vue2 CLI Plugin - Jest + +#### Mocha + +Mocha는 유연성에 중점을 둔 JavaScript 테스트 프레임워크입니다. 그래서 spying (예 : Sinon) 또는 assertion (예 : Chai)과 같은 어떠한 기능을 수행하기 위해 별도의 라이브러리를 선택해야 합니다. Mocha의 또 다른 특징은 Node.js 외에도 브라우저에서 테스트를 실행할 수 있다는 것입니다. + +**자료:** + +- Mocha 공식 웹사이트 +- 공식 Vue CLI Plugin - Mocha + +## 컴포넌트 테스팅 + +### 소개 + +대부분의 Vue 컴포넌트를 테스트하려면, 컴포넌트가 작동 중인지 확인하기 위해 DOM (가상 또는 실제)에 마운트해야합니다. 이것은 프레임워크에 구애받지 않는(framwork-agnostic) 또 다른 개념입니다. 결과적으로 컴포넌트 테스팅 프레임워크는 사용자에게 안정적인 방식으로 이를 수행 할 수있는 기능을 제공하는 동시에 Vuex, Vue Router 및 기타 Vue 플러그인에 대한 호환과 같은 Vue 고유의 편의성을 제공하기 위해 만들어졌습니다. + +### 프레임워크 선택 + +이번 섹션은 애플리케이션에 가장 적합한 컴포넌트 테스팅 프레임워크를 선택할 때 유의해야 할 사항에 대한 지침을 제공합니다. + +#### Vue 생태계와의 최적 호환성 + +첫 번째 기준 중 하나는 Vue 생태계와 컴포넌트 테스팅 라이브러리가 최대한 호환되어야 한다는 것입니다. 포괄적인 것처럼 보일 수 있지만, 염두에 두어야 할 주요 호환 영역에는 단일 파일 컴포넌트 (SFCs), Vuex, Vue Router 및 애플리케이션이 의존하는 기타 Vue 특정 플러그인이 있습니다. + +#### 최고의 오류 보고 + +테스트가 실패하면, 컴포넌트 테스팅 프레임워크는 문제를 디버깅할 때 소요되는 시간을 줄이는 데 도움이되는 유용한 오류 로그를 제공하는지가 중요합니다. 단순히 어떤 테스트가 실패했는지 알려주는 것 외에도 테스트가 실패한 이유에 대한 컨텍스트도 제공해야합니다.(예 : 예상하는 것과 전달받은 것) + +### 추천 + +#### Vue 테스팅 라이브러리 (@testing-library/vue) + +Vue 테스팅 라이브러리는 구현 세부사항에 의존하지 않고 테스팅 컴포넌트에 초점을 맞춘 도구 모음입니다. + +기본 원칙은 소프트웨어를 사용하는 방식과 유사한 테스트가 많을수록 더 많은 신뢰를 줄 수 있습니다. + +**자료:** + +- 공식 Vue 테스팅 라이브러리 웹사이트 + +#### Vue Test Utils + +Vue Test Utils는 사용자에게 Vue 특정 API에 대한 액세스를 제공하기 위해 작성된 공식 저수준 컴포넌트 테스트 라이브러리입니다. Vue 응용 프로그램을 처음 테스트하는 경우 Vue Test Utils를 추상화한 Vue Testing Library를 사용하는 것이 좋습니다. + +**자료:** + +- 공식 Vue Test Utils Documentation +- Vue 테스팅 핸드북 by Lachlan Miller + +## 종단간 (E2E) 테스팅 + +### 소개 + +단위 테스트 및 컴포넌트 테스트는 개발자에게 어느 정도의 확신을 제공하지만, 프로덕션에 배포 될 때 애플리케이션의 전체적인 범위에 대한 확신을 제공하진 못 합니다. 그 결과, E2E 테스트는 애플리케이션의 가장 중요한 측면, 즉 사용자가 실제로 애플리케이션을 사용할 때 일어나는 일에 대한 범위의 확신을 제공합니다. + +즉, E2E 테스트는 애플리케이션의 모든 계층을 검증합니다. 검증에는 프론드엔드 코드뿐 아니라 사용자가 있을 환경을 잘 나타내는 모든 백엔드 서비스 및 인프라가 포함됩니다. 사용자의 동작이 애플리케이션에 미치는 영향을 테스팅함으로써 E2E 테스트는 애플리케이션이 제대로 작동하는지에 대한 신뢰도를 높이는 열쇠가됩니다. + +### 프레임워크 선택 + +웹에서 종단간 (E2E) 테스팅은 개발 프로세스 속도 저하와 낮은 신뢰도로 부정적인 평판을 얻었지만, 최신 E2E 도구는 보다 안정적이고 대화형이며 유용한 테스트를 만들기위한 진전을 이루었습니다. 이번 섹션에서는 애플리케이션에 맞는 E2E 테스팅 프레임워크를 선택할 때 유의해야 할 몇 가지 가이드를 제공합니다. + +#### 크로스-브라우저 테스팅 + +종단간 (E2E) 테스팅의 주요 이점 중 하나는 여러 브라우저에서 애플리케이션을 테스트 할 수 있다는 것입니다. 브라우저 간 100% 적용 범위를 갖는 것이 바람직해 보일 수 있지만, 브라우저 간 테스팅은 일관적인 실행을 위한 추가 시간과 기계 성능으로 인한 팀의 리소스에 대한 수익이 감소한다는 점에 유의해야합니다. 따라서 응용 프로그램에 필요한 크로스 브라우저 테스팅의 양을 선택할 때 이러한 절충점을 염두에 두는 것이 중요합니다. + +::: 팁 브라우저 관련 문제를 포착하기 위해 최근 개발은 일반적으로 사용되지 않는 브라우저(예 : , 이전 Safari 버전 등)에 대한 애플리케이션 모니터링 및 오류보고 도구(예 : Sentry, LogRocket 등)를 사용하는 것입니다. ::: + +#### 빠른 피드백 주기 + +E2E 테스트 및 개발은 전체 제품을 실행하는데 오랜 시간이 걸립니다. 일반적으로 E2E 테스트는 CI/CD (지속적 통합 및 배포) 파이프라인에서 수행됩니다. 최신 E2E 테스팅 프레임워크는 병렬화 같은 기능을 추가하여 이 문제를 해결하는 데 도움을 주고, 이를 통해 CI/CD 파이프라인이 더 빠르게 실행됩니다. 또한 로컬에서 개발할 때, 작업중인 페이지에 대해 단일 테스트를 선택적으로 실행하는 동시에 테스트의 핫 리로딩을 제공하는 기능은 개발자의 워크플로우와 생산성을 높이는 데 도움이 될 수 있습니다. + +#### 최고의 디버깅 경험 + +개발자는 전통적으로 테스트에서 무엇이 잘못되었는지 확인하기 위해 터미널 창에서 로그를 스캔하는 데 의존해 왔지만, 현대 종단간 (E2E) 테스트 프레임워크를 사용하면 개발자가 익숙한 도구를 활용할 수 있습니다. (예 브라우저 개발자 도구) + +#### 헤드리스 모드의 가시성 + +지속적 통합/배포 파이프라인에서 계속 종단간 (E2E) 테스트를 실행하려면 헤드리스 브라우저에서 실행되는 경우가 많습니다 (즉, 사용자가 볼 수있는 브라우저가 열리지 않음). 결과적으로 오류가 발생할 때, E2E 테스팅 프레임워크가 오류 발생 원인에 대한 통찰력 제공을 위해 지원하는 기능은 다양한 테스팅 단계에서 애플리케이션의 스냅샷 또는 비디오를 볼 수 있는 기능입니다. 과거, 이러한 통합을 유지하는 것은 지루한 작업입니다. + +### 추천 + +생태계에는 많은 도구가 있지만, 다음은 Vue.js생태계에서 사용되는 일반적인 종단간 (E2E) 테스팅 프레임 워크입니다. + +#### Cypress.io + +Cypress.io는 개발자가 애플리케이션을 안정적으로 테스트하는 동시에 최고의 개발 경험을 제공함으로써 개발자 생산성을 높이는 것을 목표로하는 테스팅 프레임워크입니다. + +**자료** + +- Cypress 공식 웹사이트 +- 공식 Vue CLI Cypress Plugin +- Cypress 테스팅 라이브러리 + +#### Nightwatch.js + +Nightwatch.js는 Node.js의 단위, 통합 테스팅은 물론 웹 애플리케이션과 웹 사이트를 테스트하는 데 사용할 수 있는 종단간 테스팅 프레임워크입니다. + +**자료:** + +- Nightwatch 공식 웹사이트 +- 공식 Vue CLI Nightwatch Plugin + +#### Puppeteer + +Puppeteer는 브라우저를 제어하기 위한 고급 API를 제공하고 다른 테스트 실행기 (예 : Jest)와 연동하여 애플리케이션을 테스트할 수 있는 노드 라이브러리입니다. + +**자료:** + +- Puppeteer 공식 웹사이트 + +#### TestCafe + +TestCafe는 Node.js 기반의 단순한 프레임워크로, 개발자가 작성하기 쉽고 안정적인 테스트 작성에 집중할 수 있도록 손쉬운 설정을 제공합니다. + +**자료:** + +- [TestCafe 공식 웹사이트](https://devexpress.github.io/testcafe/) From 4ad2648aa346c57d25a38b7a99f57b26c853e375 Mon Sep 17 00:00:00 2001 From: DongKyuuuu Date: Mon, 24 Aug 2020 13:03:56 +0000 Subject: [PATCH 020/416] Translate transitions-state.md via GitLocalize --- ko-KR/src/guide/transitions-state.md | 145 +++++++++++++++++++++++++++ 1 file changed, 145 insertions(+) create mode 100644 ko-KR/src/guide/transitions-state.md diff --git a/ko-KR/src/guide/transitions-state.md b/ko-KR/src/guide/transitions-state.md new file mode 100644 index 000000000..d93551046 --- /dev/null +++ b/ko-KR/src/guide/transitions-state.md @@ -0,0 +1,145 @@ +# 상태 트랜지션 + +Vue의 트랜지션 시스템은 진입, 진출 및 목록을 애니메이션으로 만드는 많은 간단한 방법을 제공하지만 데이터 자체에 대한 애니메이션은 어떻게 해야할까요? + +- 숫자와 계산 +- 색 표시 +- SVG노드 위치 +- 엘리먼트들의 크기 및 기타 속성 + +이들 모두는 이미 원시 숫자로 저장되었거나, 숫자로 변환 될 수 있습니다. 그렇게 하면, Vue의 반응형 및 컴포넌트 시스템을 결합하여, 상태변화를 써드파티 라이브러리를 사용해 트윈 상태로 애니메이션화 할 수 있습니다. + +## Watchers를 이용한 상태 애니메이션 + +Watchers는 아무런 숫자 타입에서 다른 타입으로의 변화를 애니메이션화 하는 것을 허용합니다. 처음에는 꽤 복잡해 보일 수 있으니 [GreenSock](https://greensock.com/) 예제를 사용하여 살펴 보겠습니다. + +```html + + +
+ +

{{ animatedNumber }}

+
+``` + +```js +const Demo = { + data() { + return { + number: 0, + tweenedNumber: 0 + } + }, + computed: { + animatedNumber() { + return this.tweenedNumber.toFixed(0) + } + }, + watch: { + number(newValue) { + gsap.to(this.$data, { duration: 0.5, tweenedNumber: newValue }) + } + } +} + +Vue.createApp(Demo).mount('#animated-number-demo') +``` + +

See the Pen Transitioning State 1 by Vue (@Vue) on CodePen.

+ +숫자를 변경할 때, input 아래에 변경되는 애니메이션이 보여집니다. + +## 동적 상태 트랜지션 + +Vue의 트랜지션 컴포넌트와 마찬가지로 데이터 백업 상태 트랜지션을 실시간으로 업데이트 할 수 있으므로 프로토 타이핑에 특히 유용합니다! 간단한 SVG 폴리곤을 사용해도, 변수를 조금씩 사용하기 전까지는 생각하기 어려운 많은 효과를 얻을 수 있습니다. + +

See the Pen Updating SVG by Vue (@Vue) on CodePen.

+ +## 컴포넌트를 이용한 트랜지션 구성 + +여러 상태 트랜지션을 관리하면 Vue 인스턴스 또는 컴포넌트의 복잡성을 빠르게 높일 수 있습니다. 다행히도 많은 애니메이션을 전용 하위 컴포넌트로 추출 할 수 있습니다. 이전 예제의 숫자를 이용하는 애니메이션을 사용해 보겠습니다. + +```html + + +
+ + + = {{ result }} +

+ + + = + +

+
+``` + +```js +const app = Vue.createApp({ + data() { + return { + firstNumber: 20, + secondNumber: 40 + } + }, + computed: { + result() { + return this.firstNumber + this.secondNumber + } + } +}) + +app.component('animated-integer', { + template: '{{ fullValue }}', + props: { + value: { + type: Number, + required: true + } + }, + data() { + return { + tweeningValue: 0 + } + }, + computed: { + fullValue() { + return Math.floor(this.tweeningValue) + } + }, + methods: { + tween(newValue, oldValue) { + gsap.to(this.$data, { + duration: 0.5, + tweeningValue: newValue, + ease: 'sine' + }) + } + }, + watch: { + value(newValue, oldValue) { + this.tween(newValue, oldValue) + } + }, + mounted() { + this.tween(this.value, 0) + } +}) + +app.mount('#app') +``` + +

See the Pen State Transition Components by Vue (@Vue) on CodePen.

+ +이제 자식 컴포넌트들과 함께 다양한 상태를 구성 할 수 있습니다. Vue의 [기본 제공 트랜지션 시스템](transitions.html)에서 제공하는 트랜지션 방법과 함께 이 페이지에서 다룬 트랜지션 방법을 조합하여 사용 할 수 있습니다. 두 방법을 함께 사용하는 것에는 거의 제한사항이 없습니다. + +데이터 시각화, 물리 효과, 캐릭터 애니메이션 및 상호작용에 어떻게 무궁무진 하게 사용 할 수 있는지 알 수 있습니다. + +## 디자인에 생명을 불어넣기 + +애니메이션을 추가하는 것은 생명을 불어 넣는 일 입니다. 불행하게도 디자이너가 만든 아이콘, 로고 및 마스코트들은 이미지나 정적 SVG입니다. 그래서 Github의 octocat, Twitter의 새 및 기타 로고들은 살아있는 것들과 유사하지만 살아 움직이지는 못합니다. + +Vue가 도와줄 수 있습니다. SVG는 단순한 데이터일 뿐이므로 놀라거나, 생각할 때, 경고할때 어떻게 할 지 예시가 필요합니다. 그 다음 Vue는 데이터들을 트랜지션하여 환영페이지, 로딩 표시기, 알림을 감정적이고 매력적으로 만들 수 있습니다. + +Sarah Drasner는 타이밍과 인터랙션 중심의 상태 변화를 조합하여 아래의 데모를 만들었습니다. + +

See the Pen Vue-controlled Wall-E by Sarah Drasner (@sdras) on CodePen.

From f1163f9d2ee179c9dcb70095ae8ef36f13fa6424 Mon Sep 17 00:00:00 2001 From: DongKyuuuu Date: Mon, 24 Aug 2020 13:04:25 +0000 Subject: [PATCH 021/416] Translate transitions-overview.md via GitLocalize --- ko-KR/src/guide/transitions-overview.md | 238 ++++++++++++++++++++++++ 1 file changed, 238 insertions(+) create mode 100644 ko-KR/src/guide/transitions-overview.md diff --git a/ko-KR/src/guide/transitions-overview.md b/ko-KR/src/guide/transitions-overview.md new file mode 100644 index 000000000..8c24e5851 --- /dev/null +++ b/ko-KR/src/guide/transitions-overview.md @@ -0,0 +1,238 @@ +# 개요 + +Vue는 특히 변화에 대응하여 트랜지션 및 애니메이션 작업에 도움되는 몇 가지 추상화를 제공합니다. 추상화 중 일부는 다음과 같습니다. + +- 내장 되어 있는 `` 컴포넌트를 사용하여 DOM에 진입/진출 되는 JS 및 CSS 컴포넌트에 대한 훅(Hooks) +- 트랜지션 중에 순서를 조정할 수 있게 하는 트랜지션 모드 +- `` 컴포넌트 엘리먼트를 사용하여 성능을 높이기 위해 내부적으로 적용된 FLIP 기술과 함께 여러 엘리먼트가 바로 업데이트되는 경우의 훅(Hooks). +- `watchers`를 사용하여 애플리케이션에서의 다른 트랜지션 상태 + +이 가이드의 다음 3가지 섹션에서 모든 내용을 다룰 것 입니다. 유용한 API 제공 뿐만 아니라, 앞서 살펴본 클래스 및 스타일 선언을 사용하여 여러 예제에서 간단하게 애니메이션 및 트랜지션을 적용 할 수 있습니다. + +이 다음 섹션에서는 몇 가지 웹 애니메이션 및 트랜지션의 기본 사항을 살펴보고 좀 더 알아보기 위해 몇 가지 리소스에 연결해야 합니다. 웹 애니메이션에 이미 익숙하고, 웹 애니메이션 원리가 Vue의 일부 원리와 어떻게 작동하는지 알고 있다면이 다음 섹션을 건너 뛰어도됩니다. 깊게 알아보기 전에 웹 애니메이션 기본 사항에 대해 조금더 알고 싶은 사람은 계속 살펴봐도 됩니다. + +## 클래스 기반 애니메이션 / 트랜지션 + +``컴포넌트는 다른 컴포넌트들의 진입 / 진출에 유용합니다. 조건부 클래스를 추가하여 컴포넌트를 마운트(mounting) 하지 않고 애니메이션을 할성화 할 수 있습니다. + +```html +
+ 하지 말아야 할 일을 하려면 버튼을 눌러주세요
+ +
+ + 이런 +
+
+``` + +```css +.shake { + animation: shake 0.82s cubic-bezier(0.36, 0.07, 0.19, 0.97) both; + transform: translate3d(0, 0, 0); + backface-visibility: hidden; + perspective: 1000px; +} + +@keyframes shake { + 10%, + 90% { + transform: translate3d(-1px, 0, 0); + } + + 20%, + 80% { + transform: translate3d(2px, 0, 0); + } + + 30%, + 50%, + 70% { + transform: translate3d(-4px, 0, 0); + } + + 40%, + 60% { + transform: translate3d(4px, 0, 0); + } +} +``` + +```js +const Demo = { + data() { + return { + noActivated: false + } + } +} + +Vue.createApp(Demo).mount('#demo') +``` + +

See the Pen Create animation with a class by Vue (@Vue) on CodePen.

+ +# 스타일 바인딩과 트랜지션 + +일부 트랜지션 효과는 인터렉션(interaction)이 발생하는 동안 엘리먼트에 스타일을 바인딩하는 것과 같이 값을 보간(interpolating)하여 적용 할 수 있습니다. 예를 들면 다음과 같습니다. + +```html +
+
+

화면에서 마우스를 이동시켜보세요...

+

x: {{x}}

+
+
+``` + +```css +.movearea { + transition: 0.2s background-color ease; +} +``` + +```js +const Demo = { + data() { + return { + x: 0 + } + }, + methods: { + xCoordinate(e) { + this.x = e.clientX + } + } +} + +Vue.createApp(Demo).mount('#demo') +``` + +

See the Pen Interpolation with style bindings by Vue (@Vue) on CodePen.

+ +이 예제에서는 마우스 움직임에 포함 된 보간법(interpolation)을 사용하여 애니메이션을 만듭니다. CSS 트랜지션은 엘리먼트에도 적용되어 엘리먼트가 업데이트하는 동안 사용할 easing의 종류를 알 수 있습니다. + +## 퍼포먼스(performance) + +위에 표시된 애니메이션은 `transforms`과 같은 것을 사용하고, `perspective` 같은 독특한 프로퍼티를 적용했습니다. 왜 `margin` 과 `top` 같은 프로퍼티 대신 사용한걸 까요? + +퍼포먼스를 알고 있음으로써 웹에서 매우 부드러운 애니메이션을 만들 수 있습니다. 가능한 경우 엘리먼트가 하드웨어 가속을 할 수 있게 합니다. 그리고 repaints를 트리거 하지 않는 프로퍼티을 사용합니다. 이 작업을 수행 할 수 있는 몇가지 방법을 알아 보겠습니다. + +### Transform과 Opacity + +[CSS-Triggers](https://csstriggers.com/)와 같은 리소스를 확인하여 애니메이션을 적용하면 어떤 프로퍼티가 repaints를 트리거 하는지 확인 할 수 있습니다. 여기에서 `transform` 아래를 보면 다음과 같이 표시 됩니다. + +> transform을 변경해도 geometry가 변경 되거나, painting이 트리거 되지 않기 때문에 문제가 없습니다. 이것은 GPU의 도움으로 컴포지터(compositor) 스레드에서 작업을 수행 할 수 있음을 의미합니다. + +Opacity는 비슷하게 동작하기 때문에 웹 동작에 좋은 선택지가 될 수 있습니다. + +### 하드웨어 가속 + +`perspective`, `backface-visibility`,`transform: translateZ(x)` 같은 프로퍼티들을 사용하면 브라우저에서 하드웨어 가속이 필요한지 알 수 있습니다. + +엘리먼트의 하드웨어 가속을 원하는 경우 다음 프로퍼티 중 하나를 적용 할 수 있습니다 (모두 필요한 것은 아니며 하나만). + +```css +perspective: 1000px; +backface-visibility: hidden; +transform: translateZ(0); +``` + +GreenSock과 같은 많은 JS 라이브러리는 기본적으로 하드웨어 가속을 원한다고 가정하고 적용하므로 수동으로 설정할 필요가 없습니다. + +## 타이밍(Timing) + +단순한 UI 트랜지션의 경우(중간에 다른 상태가 없고, 시작 상태와 끝 상태만 있는 경우) 0.1s 에서 0.4s 사이의 타이밍을 사용하는 것이 일반적이고, 대부분의 사람들은 0.25s가 최적의 타이밍 이라고 생각합니다. 이 타이밍(0.25s)을 모든 트랜지션에 사용 할 수 있을까요? 아닙니다. 더 많은 위치를 이동해야 하거나, 더 많은 단계 또는 상태 변경이 필요한 경우가 있는 경우 0.25s는 최적의 타이밍이 아닐 수 있습니다. 이런 경우 더 계획적 이여야 하며 타이밍은 더 유니크 해야 합니다. 그렇다고 해서 애플리케이션 내에서 반복되어지는 타이밍 기본값을 가질 수 없는 것은 아닙니다. + +또한 진입이 진출보다 약간 더 많은 시간을 가진다면 보기에 더 좋아 보일 수 있습니다. 사용자는 일반적으로 트랜지션 진입 시 가이드(guided) 받고, 도중에 떠나고 싶어 하기 때문에 진출 까지 기다리지 못 할 수 있습니다. + +## Easing + +Easing은 애니메이션에서 깊이를 전달하는 중요한 방법입니다. 애니메이션을 처음 접하는 사람들이 저지르는 가장 일반적인 실수 중 하나는 진입 시`ease-in`을 사용하고 진출 시`ease-out`을 사용 하는 것 입니다. 사실 이것들은 서로 반대로 필요합니다. + +이러한 상태를 트랜지션에 적용하면 다음과 같이 표시 됩니다. + +```css +.button { + background: #1b8f5a; + /* 초기 상태에 적용, 트랜지션은 반환 상태에 적용 됩니다. */ + transition: background 0.25s ease-in; +} + +.button:hover { + background: #3eaf7c; + /* 호버 상태에 적용, 호버가 트리거 될 때 트랜지션이 적용 됩니다. */ + transition: background 0.35s ease-out; +} +``` + +

See the Pen Transition Ease Example by Vue (@Vue) on CodePen.

+ +Easing은 애니메이션되는 머티리얼(material)의 질감을 전달 할 수 있습니다. 아래의 예제에서, 어떤 공이 딱딱하고 어떤 공이 부드럽다고 느끼시나요? + +

See the Pen Bouncing Ball Demo by Sarah Drasner (@sdras) on CodePen.

+ +easing을 조정하여 많은 유니크한 효과를 얻고 애니메이션을 세련되게 만들 수 있습니다. CSS를 사용하면 cubic bezier 속성을 조정하여 수정 할 수 있습니다. Lea Verou의 [this playground](https://cubic-bezier.com/#.17,.67,.83,.67)에서 확인 할 수 있습니다. + +cubic-bezier ease가 제공하는 두 개의 핸들을 사용하여 간단한 애니메이션에 큰 효과를 얻을 수 있습니다. 그러나 JavaScript는 다중 핸들을 허용하기 때문에 훨씬 더 많은 차이가 있습니다. + +![Ease Comparison](/images/css-vs-js-ease.svg) + +bounce를 예로 들어 보겠습니다. CSS에서는 각 키 프레임을 위 아래로 선언해야 합니다. JavaScript에서는 [GreenSock API (GSAP)](https://greensock.com/)에서 `bounce`를 선언하여 모든 움직임을 쉽게 표현 할 수 있습니다(JS 라이브러리 마다 다른 유형의 기본값이 있습니다). + +다음은 CSS에서 bounce에 사용 되는 코드입니다.(animate.css의 예) + +```css +@keyframes bounceInDown { + from, + 60%, + 75%, + 90%, + to { + animation-timing-function: cubic-bezier(0.215, 0.61, 0.355, 1); + } + + 0% { + opacity: 0; + transform: translate3d(0, -3000px, 0) scaleY(3); + } + + 60% { + opacity: 1; + transform: translate3d(0, 25px, 0) scaleY(0.9); + } + + 75% { + transform: translate3d(0, -10px, 0) scaleY(0.95); + } + + 90% { + transform: translate3d(0, 5px, 0) scaleY(0.985); + } + + to { + transform: translate3d(0, 0, 0); + } +} + +.bounceInDown { + animation-name: bounceInDown; +} +``` + +다음은 GreenSock을 사용한 JS에서 사용되는 bounce 입니다. + +```js +gsap.from(element, { duration: 1, ease: 'bounce.out', y: -500 }) +``` + +다음 섹션의 일부 예제에서 GreenSock을 사용할 것입니다. 멋진 ease를 구축하는 데 도움이 되는 훌륭한 [ease 시각화 도구](https://greensock.com/ease-visualizer)가 있습니다. + +## 추가 읽을거리 + +- [인터페이스 애니메이션 디자인: 애니메이션을 통한 사용자 경험 향상 by Val Head](https://www.amazon.com/dp/B01J4NKSZA/) +- [Rachel Nabors의 애니메이션 작업](https://abookapart.com/products/animation-at-work) From 140ff5a16a1f0140e3a583e3ad26d7c3bfe35852 Mon Sep 17 00:00:00 2001 From: Radler Date: Mon, 24 Aug 2020 13:10:22 +0000 Subject: [PATCH 022/416] Translate computed.md via GitLocalize --- ko-KR/src/guide/computed.md | 246 ++++++++++++++++++++++++++++++++++++ 1 file changed, 246 insertions(+) create mode 100644 ko-KR/src/guide/computed.md diff --git a/ko-KR/src/guide/computed.md b/ko-KR/src/guide/computed.md new file mode 100644 index 000000000..2323f64c3 --- /dev/null +++ b/ko-KR/src/guide/computed.md @@ -0,0 +1,246 @@ +# Computed 속성과 Watch + +## Computed 속성 + +템플릿 내에 표현식을 넣으면 편리하지만, 간단한 연산을 위한 부분입니다. 템플릿 안에서 너무 많은 연산을 하면 코드가 비대해지고 유지보수가 어렵습니다. 중첩된 배열이 있는 객체를 가진 경우에 대한 아래 예제를 봅시다. + +```js +Vue.createApp({ + data() { + return { + author: { + name: '존 도우', + books: [ + 'Vue 2 - Advanced Guide', + 'Vue 3 - Basic Guide', + 'Vue 4 - The Mystery' + ] + } + } + } +}) +``` + +그리고 `author` 가 이미 책이 있는 지 여부에 따라 다른 메시지를 보여주기를 원합니다. + +```html +
+

출판된 책:

+ {{ author.books.length > 0 ? '있음' : '없음' }} +
+``` + +이 시점에서는 템플릿은 더이상 단순하고 선언적이지 않습니다. `author.books` 에 따라 계산을 수행한다는 것을 깨닫기까지 잠시 살펴봐야만 합니다. 템플릿 내에 이 계산을 한번 더 넣으려는 경우, 이 문제는 더 악화됩니다. + +그러므로 반응형 데이터를 포함하는 복잡한 로직의 경우, **Computed 속성**을 사용해야 합니다 . + +### 기본 예제 + +```html +
+

출판된 책:

+ {{ publishedBooksMessage }} +
+``` + +```js +Vue.createApp({ + data() { + return { + author: { + name: '존 도우', + books: [ + 'Vue 2 - Advanced Guide', + 'Vue 3 - Basic Guide', + 'Vue 4 - The Mystery' + ] + } + } + }, + computed: { + // computed getter + publishedBooksMessage() { + // 여기서의 `this` 는 vm 인스턴스이다. + return this.author.books.length > 0 ? '있음' : '없음' + } + } +}).mount('#computed-basics') +``` + +결과: + +

See the Pen Computed basic example by Vue (@Vue) on CodePen.

+ +우리는 여기서 `publishedBooksMessage` 라는 computed 속성을 선언했습니다. + +이 어플리케이션에서 `data` 의 `books` 배열의 값을 변경하면, 그에 따라 `publishedBooksMessage` 가 어떻게 변경되는 지 볼 수 있습니다. + +일반적인 속성과 마찬가지로 템플릿에서 computed 속성도 데이터 바인딩 할 수 있습니다. Vue 는 `vm.publishedBooksMessage`가 `vm.author.books` 에 의존한다는 것을 알고 있습니다. 그래서 `vm.author.books` 가 변경될 때 `vm.publishedBooksMessage` 에 의존하는 모든 바인딩을 업데이트합니다. 그리고 가장 좋은 부분은 종속성 관계를 선언적으로 만들었다는 것입니다. computed getter 함수에 사이드 이펙트가 없으므로 테스트하거나 이해하기에도 더 쉽습니다. + +### Computed 속성의 캐싱 vs 메서드 + +표현식에서 메서드를 호출하여 동일한 결과를 얻을 수도 있습니다. + +```html +

{{ calculateBooksMessage() }}

+``` + +```js +// 컴포넌트 내부 +methods: { + calculateBooksMessage() { + return this.author.books.length > 0 ? '있음' : '없음' + } +} +``` + +computed 속성 대신에 메서드와 동일한 함수를 정의할 수 있습니다. 최종 결과를 위해, 두가지 접근 방식은 정확히 동일합니다. 그러나 차이점은 **computed 속성은 반응형(reactive) 종속성에 기반하여 캐시된다는 것** 입니다. computed 속성은 반응형 종속성 중 일부가 변경된 경우에만 재평가됩니다. 즉, `author.books` 가 변경되지 않는다면 `publishedBooksMessage` computed 속성에 대해 여러번 접근하더라도 함수를 다시 실행할 필요없이 이전에 계산된 결과를 즉시 반환합니다. + +또한 이는 `Date.now()`이 반응형 종속성이 아니기 때문에, 다음 예제의 computed 속성이 업데이트되지 않음을 의미합니다. + +```js +computed: { + now() { + return Date.now() + } +} +``` + +이에 비해 메서드 호출은 다시 렌더링이 발생할 때마다 항상 함수를 실행합니다. + +캐싱이 필요한 이유는 무엇일까요? 거대한 배열을 반복하고 많은 계산을 수행해야 하는 값 비싼 `list` computed 속성이 있다고 상상해보십시오. 그리고 `list`에 종속적인 다른 computed 속성들이 있다고 가정해봅시다. 캐싱이 없다면, `list`의 getter는 필요한 것보다 훨씬 많이 실행될 것입니다! 캐싱을 원하지 않는 경우라면, `method` 를 사용하십시오. + +### Computed 속성의 Setter + +Computed 속성은 기본적으로 getter 이지만, 필요할 때엔 setter 도 제공할 수 있습니다. + +```js +// ... +computed: { + fullName: { + // getter + get() { + return this.firstName + ' ' + this.lastName + }, + // setter + set(newValue) { + const names = newValue.split(' ') + this.firstName = names[0] + this.lastName = names[names.length - 1] + } + } +} +// ... +``` + +이제 `vm.fullName = 'John Doe'`를 실행하면, setter가 호출되고 `vm.firstName`과 `vm.lastName`이 그에 따라 업데이트 됩니다. + +## Watch 속성 + +대부분의 경우 computed 속성이 더 적절하지만, 사용자 지정 감시자(watcher) 가 필요한 경우도 있습니다. 이것이 Vue 가 `watch` 옵션을 통해 데이터의 변경에 대응하는 방법을 제공하는 이유입니다. 이는 데이터 변경에 대한 응답으로 비동기 혹은 비용이 많이 드는 작업을 수행하려는 경우가 가장 유용합니다. + +아래 예제를 봅시다. + +```html +
+

+ 예/아니오 질문을 물어보세요. + +

+

{{ answer }}

+
+``` + +```html + + + + + +``` + +결과: + +

See the Pen Watch basic example by Vue (@Vue) on CodePen.

+ +이 경우 `watch` 옵션을 사용하면 비동기 작업 (API 접근)을 수행하고, 이 작업을 수행하기 위한 조건을 설정할 수 있습니다. computed 속성은 이러한 기능을 수행할 수 없습니다. + +추가로 `watch` 옵션 외에도 명령형 [vm.$watch API](../api/instance-methods.html#watch)를 사용할 수 있습니다. + +### Computed 속성 vs Watch 속성 + +Vue는 현재 활성화된 인스턴스에서 데이터 변경을 관찰하고 이에 반응하는 좀 더 일반적인 방법인 **watch 속성**을 제공합니다. 다른 데이터를 기반으로 변경해야 하는 데이터가 있는 경우, `watch` 를 과도하게 쓰고자 하는 유혹이 있습니다. 특히 AngularJS 기반에서 온 경우 그렇습니다. 그러나 명령형 `watch` 콜백보다 computed 속성을 쓰는 것이 더 나은 경우가 많습니다. 아래 예제를 봅시다. + +```html +
{{ fullName }}
+``` + +```js +const vm = Vue.createApp({ + data() { + return { + firstName: 'Foo', + lastName: 'Bar', + fullName: 'Foo Bar' + } + }, + watch: { + firstName(val) { + this.fullName = val + ' ' + this.lastName + }, + lastName(val) { + this.fullName = this.firstName + ' ' + val + } + } +}).mount('#demo') +``` + +위 코드는 명령형이고 또 코드를 반복합니다.
아래의 computed 속성을 사용하는 방식과 비교해보세요. + +```js +const vm = Vue.createApp({ + data() { + return { + firstName: 'Foo', + lastName: 'Bar' + } + }, + computed: { + fullName() { + return this.firstName + ' ' + this.lastName + } + } +}).mount('#demo') +``` + +훨씬 낫지 않습니까? From f830b14b4d1edaf71cf4be07347d9ad52b0e4391 Mon Sep 17 00:00:00 2001 From: Yunsup Sim Date: Mon, 24 Aug 2020 13:11:07 +0000 Subject: [PATCH 023/416] Translate filters.md via GitLocalize --- ko-KR/src/guide/migration/filters.md | 74 ++++++++++++++++++++++++++++ 1 file changed, 74 insertions(+) create mode 100644 ko-KR/src/guide/migration/filters.md diff --git a/ko-KR/src/guide/migration/filters.md b/ko-KR/src/guide/migration/filters.md new file mode 100644 index 000000000..e333f91b9 --- /dev/null +++ b/ko-KR/src/guide/migration/filters.md @@ -0,0 +1,74 @@ +--- +badges: +- 제거됨 +--- + +# Filters + +## 개요 + +Filters는 Vue 3.0에서 제거되며 더 이상 지원되지 않습니다. + +## 2.x 구문 + +2.x 버전에서는 텍스트 형식화(common text formatting)을 할 수 있는 filters를 사용할 수 있었습니다. + +예시: + +```html + + + +``` + +위의 방식은 편리해 보이지만, 중괄호 보간법 안의 표현식이 "그냥 자바스크립트"라는 전제를 깨는 맞춤형 구문이 필요하고, 이는 filters를 배우고 적용하는데에 비용이 들게 합니다. + +## 3.x 변경 + +3.x 버전에서는 filter는 삭제되었고 더 이상 지원되지 않습니다. 대신에 method 호출이나 computed properties로 대체하는 것이 권장됩니다. + +다음은 filters대신에 computed properties를 적용해 구현한 예시입니다. + +```html + + + +``` + +## 마이그레이션 방법 + +filters 대신 methods나 computed properties를 사용하는 것을 권장합니다. From 76ca4e79a4a0d8f0e8cb9daedfd9f232d60c129b Mon Sep 17 00:00:00 2001 From: DongKyuuuu Date: Mon, 24 Aug 2020 13:20:06 +0000 Subject: [PATCH 024/416] Translate transitions-list.md via GitLocalize --- ko-KR/src/guide/transitions-list.md | 422 ++++++++++++++++++++++++++++ 1 file changed, 422 insertions(+) create mode 100644 ko-KR/src/guide/transitions-list.md diff --git a/ko-KR/src/guide/transitions-list.md b/ko-KR/src/guide/transitions-list.md new file mode 100644 index 000000000..9f7bc8ef9 --- /dev/null +++ b/ko-KR/src/guide/transitions-list.md @@ -0,0 +1,422 @@ +# 리스트 트랜지션 + +지금까지 다음과 같은 트랜지션을 다루었습니다. + +- 개별 노드들 +- 한번에 하나만 렌더링 되는 여러 노드 + +그렇다면 `v-for`를 사용하여 동시에 렌더링 하고자 하는 항목의 전체 목록이 있는 경우는 어떨까요? 이 경우 우리는 `` 컴포넌트를 사용합니다. 예를 들어보기 전에 이 컴포넌트에 대해 알아야 할 몇 가지 중요한 사항이 있습니다. + +- ``, 과 달리, 실제 요소인 ``을 렌더링합니다. `tag` 속성으로 렌더링 된 요소를 변경할 수 있습니다. +- [트랜지션 모드](/guide/transitions-enterleave#transition-modes)를 사용할 수 없습니다. 더 이상 상호 배타적인 엘리먼트를 번갈아 사용하지 않습니다. +- Elements inside are **always required** to have a unique `key` attribute. +- CSS 트랜지션 클래스는 그룹 / 컨테이너 자체가 아닌 내부 엘리먼트에 적용됩니다. + +### 리스트의 진입 / 진출 트랜지션 + +이제 이전에 사용한 것과 같은 CSS 클래스를 사용하여 진입 / 진출의 간단한 예제를 살펴 보겠습니다. + +```html +
+ + + + + {{ item }} + + +
+``` + +```js +const Demo = { + data() { + return { + items: [1, 2, 3, 4, 5, 6, 7, 8, 9], + nextNum: 10 + } + }, + methods: { + randomIndex() { + return Math.floor(Math.random() * this.items.length) + }, + add() { + this.items.splice(this.randomIndex(), 0, this.nextNum++) + }, + remove() { + this.items.splice(this.randomIndex(), 1) + } + } +} + +Vue.createApp(Demo).mount('#list-demo') +``` + +```css +.list-item { + display: inline-block; + margin-right: 10px; +} +.list-enter-active, +.list-leave-active { + transition: all 1s ease; +} +.list-enter-from, +.list-leave-to { + opacity: 0; + transform: translateY(30px); +} +``` + +

See the Pen Transition List by Vue (@Vue) on CodePen.

+ +이 예제에는 한 가지 문제점이 있습니다. 항목을 추가하거나 제거 할 때 항목이 원활하게 트랜지션되는 대신 새 위치에 즉시 변경됩니다. 나중에 해결할 것입니다. + +### 리스트 이동 트랜지션 + +The `` component has another trick up its sleeve. It can not only animate entering and leaving, but also changes in position. The only new concept you need to know to use this feature is the addition of **the `v-move` class**, which is added when items are changing positions. Like the other classes, its prefix will match the value of a provided `name` attribute and you can also manually specify a class with the `move-class` attribute. + +이 클래스는 다음과 같이 트랜지션 타이밍과 easing curve을 지정하는 데 유용합니다. + +```html + + +
+ + +
  • + {{ item }} +
  • +
    +
    +``` + +```js +const Demo = { + data() { + return { + items: [1, 2, 3, 4, 5, 6, 7, 8, 9] + } + }, + methods: { + shuffle() { + this.items = _.shuffle(this.items) + } + } +} + +Vue.createApp(Demo).mount('#flip-list-demo') +``` + +```css +.flip-list-move { + transition: transform 0.8s ease; +} +``` + +

    See the Pen Transition-group example by Vue (@Vue) on CodePen.

    + +이것은 마술처럼 보일지 모르겠지만 Vue는 [FLIP](https://aerotwist.com/blog/flip-your-animations/)이라는 간단한 애니메이션 기법을 사용하여 변형을 사용하여 이전 위치에서 새로운 위치로 요소를 부드럽게 트랜지션합니다. + +이 기술을 이전 구현과 결합하여 가능한 모든 변경 사항을 목록에 적용 할 수 있습니다! + +```html + + +
    + + + + + + {{ item }} + + +
    +``` + +```js +const Demo = { + data() { + return { + items: [1, 2, 3, 4, 5, 6, 7, 8, 9], + nextNum: 10 + } + }, + methods: { + randomIndex() { + return Math.floor(Math.random() * this.items.length) + }, + add() { + this.items.splice(this.randomIndex(), 0, this.nextNum++) + }, + remove() { + this.items.splice(this.randomIndex(), 1) + }, + shuffle() { + this.items = _.shuffle(this.items) + } + } +} + +Vue.createApp(Demo).mount('#list-complete-demo') +``` + +```css +.list-complete-item { + transition: all 0.8s ease; + display: inline-block; + margin-right: 10px; +} + +.list-complete-enter-from, +.list-complete-leave-to { + opacity: 0; + transform: translateY(30px); +} + +.list-complete-leave-active { + position: absolute; +} +``` + +

    See the Pen Transition-group example by Vue (@Vue) on CodePen.

    + +::: tip 한 가지 중요한 사실은 이러한 FLIP 트랜지션은 `display: inline` 으로 설정된 요소로는 작동하지 않는다는 것입니다. 또는 `display: inline-block` 을 사용하거나 flex 컨텍스트에 요소를 배치 할 수 있습니다. ::: + +이러한 FLIP 애니메이션은 단일 축으로 제한되지 않습니다. 다차원 그리드의 항목을 [매우 쉽게](https://codesandbox.io/s/github/vuejs/vuejs.org/tree/master/src/v2/examples/vue-20-list-move-transitions) 트랜지션 할 수 있습니다. + +TODO: example + +### 스태거링 목록 트랜지션 + +JavaScript 트랜지션과 통신함으로써 목록 내 각 항목의 데이터 속성을 이용해 트랜지션을 스태거(stagger) 되도록 할 수 있습니다. + +```html + + +
    + + +
  • + {{ item.msg }} +
  • +
    +
    +``` + +```js +const Demo = { + data() { + return { + query: '', + list: [ + { msg: '세종대왕' }, + { msg: '이순신' }, + { msg: '정약용' }, + { msg: '김구' }, + { msg: '유관순' } + ] + } + }, + computed: { + computedList() { + var vm = this + return this.list.filter(item => { + return item.msg.toLowerCase().indexOf(vm.query.toLowerCase()) !== -1 + }) + } + }, + methods: { + beforeEnter(el) { + el.style.opacity = 0 + el.style.height = 0 + }, + enter(el, done) { + gsap.to(el, { + opacity: 1, + height: '1.6em', + delay: el.dataset.index * 0.15, + onComplete: done + }) + }, + leave(el, done) { + gsap.to(el, { + opacity: 0, + height: 0, + delay: el.dataset.index * 0.15, + onComplete: done + }) + } + } +} + +Vue.createApp(Demo).mount('#demo') +``` + +

    See the Pen Staggered Lists by Vue (@Vue) on CodePen.

    + +## 트랜지션 재사용 + +트랜지션은 Vue의 컴포넌트 시스템을 통해 재사용 할 수 있습니다. 재사용 할 수있는 트랜지션을 만드려면 루트에 `` 또는 `` 컴포넌트를 놓은 다음 자식을 트랜지션 컴포넌트에 전달하면됩니다. + +TODO: refactor to Vue 3 + +다음은 템플릿 컴포넌트를 사용하는 예입니다. + +```js +Vue.component('my-special-transition', { + template: '\ + \ + \ + \ + ', + methods: { + beforeEnter(el) { + // ... + }, + afterEnter(el) { + // ... + } + } +}) +``` + +[함수형 컴포넌트](render-function.html#Functional-Components)는 특히 이 작업에 적합합니다. + +```js +Vue.component('my-special-transition', { + functional: true, + render: function(createElement, context) { + var data = { + props: { + name: 'very-special-transition', + mode: 'out-in' + }, + on: { + beforeEnter(el) { + // ... + }, + afterEnter(el) { + // ... + } + } + } + return createElement('transition', data, context.children) + } +}) +``` + +## 동적 트랜지션 + +맞습니다, Vue의 트랜지션도 데이터 기반입니다! 동적 변환의 가장 기본적인 예제는 `name` 속성을 동적 속성에 바인딩합니다. + +```html + + + +``` + +이것은 Vue의 트랜지션 클래스 규칙을 사용하여 CSS 트랜지션 / 애니메이션을 정의하고 트랜지션하려는 경우에 유용 할 수 있습니다. + +실제로 모든 트랜지션 속성은 동적으로 바인딩 될 수 있습니다. 그리고 그것은 단순한 속성이 아닙니다. 이벤트 훅은 메소드이기 때문에 컨텍스트의 모든 데이터에 접근 할 수 있습니다. 즉, 컴포넌트의 상태에 따라 JavaScript 트랜지션이 다르게 동작 할 수 있습니다. + +```html + + +
    + 사라지기: + + 나타나기: + + +

    hello

    +
    + + +
    +``` + +```js +const app = Vue.createApp({ + data() { + return { + show: true, + fadeInDuration: 1000, + fadeOutDuration: 1000, + maxFadeDuration: 1500, + stop: true + } + }, + mounted() { + this.show = false + }, + methods: { + beforeEnter(el) { + el.style.opacity = 0 + }, + enter(el, done) { + var vm = this + Velocity( + el, + { opacity: 1 }, + { + duration: this.fadeInDuration, + complete: function() { + done() + if (!vm.stop) vm.show = false + } + } + ) + }, + leave(el, done) { + var vm = this + Velocity( + el, + { opacity: 0 }, + { + duration: this.fadeOutDuration, + complete: function() { + done() + vm.show = true + } + } + ) + } + } +}) + +app.mount('#dynamic-fade-demo') +``` + +TODO: example + +마지막으로, 동적 트랜지션을 만드는 궁극적인 방법은 사용되는 트랜지션의 특성을 변경하기 위해 props을 받는 컴포넌트를 사용하는 것입니다. 별로인 것 처럼 들리지만, 실제로 유일한 한계는 당신의 상상력에 있습니다. From eb289952620cf5743ef53da6d751fe4860d46071 Mon Sep 17 00:00:00 2001 From: "Jisung, Ahn" Date: Mon, 24 Aug 2020 13:20:08 +0000 Subject: [PATCH 025/416] Translate transitions-list.md via GitLocalize --- ko-KR/src/guide/transitions-list.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ko-KR/src/guide/transitions-list.md b/ko-KR/src/guide/transitions-list.md index 9f7bc8ef9..5e05a76aa 100644 --- a/ko-KR/src/guide/transitions-list.md +++ b/ko-KR/src/guide/transitions-list.md @@ -9,7 +9,7 @@ - ``, 과 달리, 실제 요소인 ``을 렌더링합니다. `tag` 속성으로 렌더링 된 요소를 변경할 수 있습니다. - [트랜지션 모드](/guide/transitions-enterleave#transition-modes)를 사용할 수 없습니다. 더 이상 상호 배타적인 엘리먼트를 번갈아 사용하지 않습니다. -- Elements inside are **always required** to have a unique `key` attribute. +- 내부의 엘리먼트는 고유한 `key` 속성을 **항상 가져야 합니다 ** - CSS 트랜지션 클래스는 그룹 / 컨테이너 자체가 아닌 내부 엘리먼트에 적용됩니다. ### 리스트의 진입 / 진출 트랜지션 @@ -74,7 +74,7 @@ Vue.createApp(Demo).mount('#list-demo') ### 리스트 이동 트랜지션 -The `` component has another trick up its sleeve. It can not only animate entering and leaving, but also changes in position. The only new concept you need to know to use this feature is the addition of **the `v-move` class**, which is added when items are changing positions. Like the other classes, its prefix will match the value of a provided `name` attribute and you can also manually specify a class with the `move-class` attribute. +`` 컴포넌트는 멋진 기능을 제공합니다. 리스트에 항목이 추가 제어될때의 진입과 진출 트랜지션 뿐만이 아니라, 목록상에서 위치가 변경될때에도 트랜지션을 제공합니다. 단지 아이템이 이동할때 사용될 ** `v-move`클래스**만 추가하면 됩니다. 다른 클래스와 마찬가지로 접두어는 제공된 `name` 속성 값과 일치하며 `move-class` 속성을 사용하여 클래스를 수동으로 지정할 수도 있습니다. 이 클래스는 다음과 같이 트랜지션 타이밍과 easing curve을 지정하는 데 유용합니다. From dec6f5d6824eee7b9f270d64ee55120552ae311d Mon Sep 17 00:00:00 2001 From: DongKyuuuu Date: Mon, 24 Aug 2020 13:20:41 +0000 Subject: [PATCH 026/416] Translate transitions-enterleave.md via GitLocalize --- ko-KR/src/guide/transitions-enterleave.md | 545 ++++++++++++++++++++++ 1 file changed, 545 insertions(+) create mode 100644 ko-KR/src/guide/transitions-enterleave.md diff --git a/ko-KR/src/guide/transitions-enterleave.md b/ko-KR/src/guide/transitions-enterleave.md new file mode 100644 index 000000000..f1998ee88 --- /dev/null +++ b/ko-KR/src/guide/transitions-enterleave.md @@ -0,0 +1,545 @@ +# 진입 / 진출 트랜지션 + +Vue는 항목이 DOM에 삽입, 갱신 또는 제거 될 때 트랜지션 효과를 적용하는 다양한 방법을 제공합니다. 여기에는 다음과 같은 도구가 포함됩니다. + +- CSS 트랜지션 및 애니메이션을 위한 클래스를 자동으로 적용합니다. +- [Animate.css](https://animate.style/)와 같은 써드파티 CSS 애니메이션 라이브러리 통합 +- 트랜지션 훅 중에 JavaScript를 사용하여 DOM을 직접 조작 +- JavaScript 써드파티 애니메이션 라이브러리 통합 + +이 페이지에서는 진입, 진출 및 목록 트랜지션만 다루지만 다음 섹션에서는 [트랜지션 상태 관리](transitions-state.html)를 볼 수 있습니다. + +## 단일 엘리먼트 / 컴포넌트 트랜지션 + +Vue는 `트랜지션`을 감싸는 컴포넌트를 제공하므로 다음과 같은 상황에서 모든 엘리먼트 또는 컴포넌트에 대한 진입 / 진출 트랜지션을 추가 할 수 있습니다. + +- 조건부 랜더링 (`v-if` 사용) +- 조건부 출력 (`v-show` 사용) +- 동적 컴포넌트 +- 컴포넌트 루트 노드 + +간단한 예제를 살펴보겠습니다. + +```html +
    + + + +

    hello

    +
    +
    +``` + +```js +const Demo = { + data() { + return { + show: true + } + } +} + +Vue.createApp(Demo).mount('#demo') +``` + +```css +.fade-enter-active, +.fade-leave-active { + transition: opacity 0.5s ease; +} + +.fade-enter-from, +.fade-leave-to { + opacity: 0; +} +``` + +

    See the Pen Simple Transition Component by Vue (@Vue) on CodePen.

    + +`transition` 컴포넌트로 싸여진 엘리먼트가 삽입되거나 제거 될 때 발생합니다. + +1. Vue는 대상 엘리먼트에 CSS 트랜지션 또는 애니메이션이 적용되었는지 여부를 자동으로 감지합니다. 그렇다면 CSS 트랜지션 클래스가 적절한 타이밍에 추가 / 제거됩니다. + +2. 트랜지션 컴포넌가 [JavaScript 훅](#javascript-hooks)를 제공하면, 훅은 적절한 타이밍에 호출됩니다. + +3. CSS 트랜지션 / 애니메이션이 감지되지 않고 JavaScript 훅이 제공 되지 않으면 삽입 또는 제거를 위한 DOM 작업이 다음 프레임에서 즉시 실행됩니다 (참고: 이는 Vue의 `nextTick` 개념과는 다른 브라우저 애니메이션 프레임입니다). + +### 트랜지션 클래스 + +진입 / 진출 트랜지션에는 6가지 클래스가 적용 됩니다. + +1. `v-enter-from`: enter의 시작 상태. 엘리먼트가 삽입되기 전에 적용되고 한 프레임 후에 제거됩니다. + +2. `v-enter-active`: enter의 활성 상태. 전체 진입 단계 동안 적용됩니다. 엘리먼트가 삽입되기 전에 적용됩니다. 트랜지션 / 애니메이션이 완료되면 제거됩니다. 이 클래스는 진입 트랜지션에서 duration, delay, easing curve를 정의 하는데 사용 될 수 있습니다. + +3. `v-enter-to`: **2.1.8 이상 버전에서 지원합니다.**진입 상태의 끝에서 실행됩니다. 엘리먼트가 삽입된 후(동시에`v-enter` 가 제거됨) 트랜지션/애니메이션이 끝나면 제거되는 하나의 프레임을 추가했습니다. + +4. `v-leave-from`: leave를 위한 시작 상태. 진출 트랜지션이 트리거 될 때 적용되고 한 프레임 후에 제거됩니다. + +5. `v-leave-active`: leave의 활성 상태. 전체 진출 상태에서 적용됩니다. 진출 트랜지션이 트리거되면 적용되고 트랜지션 / 애니메이션이 완료되면 제거됩니다. 이 클래스는 진출 트랜지션에서 duration, delay, easing curve를 정의 하는데 사용 될 수 있습니다. + +6. `v-leave-to`: **2.1.8 이상 버전에서 지원합니다.** 진출 상태 끝에서 실행됩니다. 진출 트랜지션이 트리거되고 (동시에 `v-leave` 가 제거됨) 트랜지션 / 애니메이션이 끝나면 제거되는 하나의 프레임을 추가 했습니다. + +![Transition Diagram](/images/transition.png) TODO: update diagram + +각 클래스에는 트랜지션 이름이 접두어로 붙습니다. 여기서 `v-` 접두어는 이름없이 `` 를 사용할 때의 기본 값 입니다. 예를 들어 `` 을 사용하면, `v-enter-from` 클래스는 `my-transition-enter-from` 클래스로 대체됩니다. + +`v-enter-active` 와 `v-leave-active` 는 진입 / 진출 트랜지션을 위한 다른 easing curves를 지정할 수 있는 기능을 제공합니다. 다음 섹션에서 예제를 확인 할 수 있습니다. + +### CSS 트랜지션 + +가장 일반적인 트랜지션 유형 중 하나는 CSS 트랜지션을 사용합니다. 다음은 간단한 예제 입니다. + +```html +
    + + + +

    안녕

    +
    +
    +``` + +```js +const Demo = { + data() { + return { + show: true + } + } +} + +Vue.createApp(Demo).mount('#demo') +``` + +```css +/* 진입/진출 애니메이션은 다른 durantion 및 */ +/* 타이밍 기능을 사용 할 수 있습니다. */ +.slide-fade-enter-active { + transition: all 0.3s ease-out; +} + +.slide-fade-leave-active { + transition: all 0.8s cubic-bezier(1, 0.5, 0.8, 1); +} + +.slide-fade-enter-from, +.slide-fade-leave-to { + transform: translateX(20px); + opacity: 0; +} +``` + +

    See the Pen Different Enter and Leave Transitions by Vue (@Vue) on CodePen.

    + +### CSS 애니메이션 + +CSS 애니메이션은 CSS 트랜지션과 같은 방식으로 적용됩니다. 차이점은 엘리먼트가 삽입 된 직후에 `v-enter-from`가 즉시 제거되지 않지만`animationend` 이벤트에 있습니다. + +다음은 간결함을 위해 접두사가 붙은 CSS 규칙을 생략 한 예입니다. + +```html +
    + + +

    + Lorem ipsum dolor sit amet, consectetur adipiscing elit. Mauris facilisis + enim libero, at lacinia diam fermentum id. Pellentesque habitant morbi + tristique senectus et netus. +

    +
    +
    +``` + +```js +const Demo = { + data() { + return { + show: true + } + } +} + +Vue.createApp(Demo).mount('#demo') +``` + +```css +.bounce-enter-active { + animation: bounce-in 0.5s; +} +.bounce-leave-active { + animation: bounce-in 0.5s reverse; +} +@keyframes bounce-in { + 0% { + transform: scale(0); + } + 50% { + transform: scale(1.5); + } + 100% { + transform: scale(1); + } +} +``` + +

    See the Pen CSS Animation Transition Example by Vue (@Vue) on CodePen.

    + +### 사용자 지정 트랜지션 클래스 + +다음 속성을 제공하여 사용자 정의 트랜지션 클래스를 지정할 수도 있습니다. + +- `enter-from-class` +- `enter-active-class` +- `enter-to-class` (2.1.8+) +- `leave-from-class` +- `leave-active-class` +- `leave-to-class` (2.1.8+) + +이것들은 원본 클래스 명을 오버라이드 합니다. 이는 Vue의 트랜지션 시스템을 [Animate.css](https://daneden.github.io/animate.css/)와 같은 기존 CSS 애니메이션 라이브러리와 결합하려는 경우 특히 유용합니다. + +예제 입니다. + +```html + + +
    + + + +

    안녕

    +
    +
    +``` + +```js +const Demo = { + data() { + return { + show: true + } + } +} + +Vue.createApp(Demo).mount('#demo') +``` + +### 트랜지션과 애니메이션을 함께 사용하기 + +Vue는 트랜지션이 종료 된 시점을 알기 위해 이벤트 리스너를 연결해야합니다. 적용된 CSS 규칙의 유형에 따라 `transitionend`또는 `animationend` 가 될 수 있습니다. 둘 중 하나만 사용하는 경우 Vue는 올바른 유형을 자동으로 감지 할 수 있습니다. + +그러나 어떤 경우에는 같은 엘리먼트 (예: Vue에 의해 트리거 된 CSS 애니메이션)와 함께 호버에 대한 CSS 트랜지션 효과를 둘 다 가질 수도 있습니다. 이러한 경우,`type` 속성에서 Vue가 지켜 볼 타입을 명시적으로 선언해야 합니다. 값은 `animation` 또는 `transition` 입니다. + +### 명시적 트랜지션 지속 시간 + +TODO: validate and provide an example + +> 2.2.0 버전에서 추가됨 + +대부분의 경우 Vue는 트랜지션이 완료를 자동으로 감지할 수 있습니다. 기본적으로 Vue는 루트 트랜지션 엘리먼트에서 첫 번째 `transitionend` 또는 `animationend` 이벤트를 기다립니다. 그러나 이것은 항상 이상적인 것은 아닙니다. 예를 들어, 중첩 된 내부 엘리먼트가 루트 트랜지션 엘리먼트보다 지연된 트랜지션 또는 더 긴 트랜지션 기간을 갖는 다른 엘리먼트와 함께 진행하는 트랜지션 시퀀스를 가질 수 있습니다. + +이 경우, `` 컴포넌트에 `duration` 속성을 사용하여 명시적인 트랜지션 지속 시간(밀리 초)을 지정할 수 있습니다. + +```html +... +``` + +진입과 진출 기간에도 명시적인 값을 지정할 수 있습니다. + +```html +... +``` + +### JavaScript 훅 + +속성에서 JavaScript 훅을 정의할 수 있습니다. + +```html + + + +``` + +```js +// ... +methods: { + // -------- + // 진입 + // -------- + + beforeEnter(el) { + // ... + }, + // done 콜백은 CSS와 함께 사용할 때 선택 사항입니다. + enter(el, done) { + // ... + done() + }, + afterEnter(el) { + // ... + }, + enterCancelled(el) { + // ... + }, + + // -------- + // 진출 + // -------- + + beforeLeave(el) { + // ... + }, + // done 콜백은 CSS와 함께 사용할 때 선택 사항입니다. + leave(el, done) { + // ... + done() + }, + afterLeave(el) { + // ... + }, + // leaveCancelled은 v-show와 함께 사용됩니다. + leaveCancelled(el) { + // ... + } +} +``` + +이러한 훅은 CSS 트랜지션 / 애니메이션과 조합하여 사용하거나, 자체적으로 사용 할 수 있습니다. + +JavaScript 전용 트랜지션을 하는 경우 ** `enter` 및 `leave` 훅에서 `done` 콜백이 필요합니다.** 그렇지 않으면 동기적으로 호출되고 트랜지션 즉시 완료됩니다. Vue가 CSS 탐지를 건너 뛸 수 있도록 JavaScript 전용 트랜지션에 `:css="false"` 를 명시적으로 추가하는 것도 좋은 생각입니다. 이것은 조금 더 효율적일 뿐만 아니라 CSS 규칙이 실수로 트랜지션을 방해하는 것을 방지합니다. + +[GreenSock](https://greensock.com/)를 사용하여 JavaScript 트랜지션의 예제를 살펴봅시다. + +```html + + +
    + + + +

    + Demo +

    +
    +
    +``` + +```js +const Demo = { + data() { + return { + show: false + } + }, + methods: { + beforeEnter(el) { + gsap.set(el, { + scaleX: 0.8, + scaleY: 1.2 + }) + }, + enter(el, done) { + gsap.to(el, { + duration: 1, + scaleX: 1.5, + scaleY: 0.7, + opacity: 1, + x: 150, + ease: 'elastic.inOut(2.5, 1)', + onComplete: done + }) + }, + leave(el, done) { + gsap.to(el, { + duration: 0.7, + scaleX: 1, + scaleY: 1, + x: 300, + ease: 'elastic.inOut(2.5, 1)' + }) + gsap.to(el, { + duration: 0.2, + delay: 0.5, + opacity: 0, + onComplete: done + }) + } + } +} + +Vue.createApp(Demo).mount('#demo') +``` + +

    See the Pen JavaScript Hooks Transition by Vue (@Vue) on CodePen.

    + +## 최초 렌더링 시 트랜지션 + +노드의 초기 렌더에 트랜지션을 적용하고 싶다면 `appear` 속성을 추가 할 수 있습니다 + +```html + + + +``` + +## 엘리먼트 간 트랜지션 + +[컴포넌트 사이의 트랜지션](#transitioning-between-components)에 대해서는 나중에 설명하지만 `v-if`/`v-else`를 사용하여 원본 엘리먼트 사이를 트랜지션 할 수도 있습니다. 가장 일반적인 두 엘리먼트 트랜지션 중 하나는 목록 컨테이너와 빈 목록을 설명하는 메시지 사이에 사용됩니다. + +```html + + + +
    +

    죄송합니다, 아이템을 찾을 수 없습니다.

    +
    +``` + +`v-if`를 사용하거나 단일 엘리먼트를 동적 속성에 바인딩하여 원하는 만큼의 엘리먼트 간에 트랜지션이 가능합니다. 예를 들어: + +TODO: rewrite example and put in codepen example + +```html + + + + + +``` + +다음과 같이 쓸 수도 있습니다. + +```html + + + +``` + +```js +// ... +computed: { + buttonMessage() { + switch (this.docState) { + case 'saved': return 'Edit' + case 'edited': return 'Save' + case 'editing': return 'Cancel' + } + } +} +``` + +### 트랜지션 모드 + +아직 한 가지 문제가 있습니다. 아래 버튼을 클릭 해보십시오: + +

    See the Pen Transition Modes Button Problem by Vue (@Vue) on CodePen.

    + +“on”버튼과 “off”버튼 사이를 트랜지션 할 때 두 버튼이 렌더링됩니다 - 다른 트랜지션이 진행되는 동안 하나의 트랜지션이 트랜지션됩니다. 이것은 ``의 기본 동작입니다 - 진입 / 진출이 동시에 발생합니다. + +트랜지션 항목이 서로의 위에 절대적으로 배치되는 경우 훌륭하게 작동합니다 + +

    See the Pen Transition Modes Button Problem- positioning by Vue (@Vue) on CodePen.

    + +가끔 동시에 진입 / 진출 되는 것이 필요한 것이 아니거나, 복잡한 진입 / 진출 상태를 조정해야 할 때가 있습니다. 그래서 Vue는 **트랜지션 모드** 라는 유용한 도구를 제공합니다. + +- `in-out`: 처음에는 새로운 엘리먼트가 트랜지션되고, 완료되면 현재 엘리먼트가 트랜지션됩니다. +- `out-in`: 현재 엘리먼트가 먼저 트랜지션되고, 완료되면 새로운 요소가 바뀝니다. + +::: 팁 `out-in`은 대부분의 경우에 사용 되는 상태 라는 것을 깨닫게 될 것 입니다 :) ::: + +이제 `out-in` 으로 on/off 버튼의 트랜지션을 업데이트 해 보겠습니다. + +```html + + + +``` + +

    See the Pen Transition Modes Button Problem- solved by Vue (@Vue) on CodePen.

    + +단순한 속성 추가를 통해 특수 스타일을 추가하지 않고 원래의 트랜지션을 수정했습니다. + +이 기능을 사용하여 아래 예제의 카드들 보다 더 다양한 움직임을 만들 수 있습니다. 실제로 진입 / 진출간에 트랜지션되는 두 엘리먼트 이지만, 시작 상태와 끝 상태가 도일하게 크기가 조정 되기 때문에 수평적으로 0이 되어 보입니다. 하나의 fluid한 이동처럼 보일 수 있습니다. 이런 유형의 수정은 현실감 있는 UI microinteractions에 매우 유용할 수 있습니다. + +

    See the Pen Transition Modes Flip Cards by Vue (@Vue) on CodePen.

    + +## 컴포넌트 간 트랜지션 + +컴포넌트 사이의 트랜지션은 더욱 간단합니다. 우리는 `key` 속성이 필요 없습니다. 대신, 우리는 [동적 컴포넌트](components.html#Dynamic-Components)를 래핑합니다. + +TODO: update to Vue 3 + +```html + + + +``` + +```js +new Vue({ + el: '#transition-components-demo', + data: { + view: 'v-a' + }, + components: { + 'v-a': { + template: '
    Component A
    ' + }, + 'v-b': { + template: '
    Component B
    ' + } + } +}) +``` + +```css +.component-fade-enter-active, +.component-fade-leave-active { + transition: opacity 0.3s ease; +} +.component-fade-enter, .component-fade-leave-to +/* .component-fade-leave-active below version 2.1.8 */ { + opacity: 0; +} +``` + +TODO: example From 9f188d952020f1654084fd6f9ee23c334474eb69 Mon Sep 17 00:00:00 2001 From: Haneul Cho Date: Mon, 24 Aug 2020 13:20:50 +0000 Subject: [PATCH 027/416] Translate keycode-modifiers.md via GitLocalize --- .../src/guide/migration/keycode-modifiers.md | 56 +++++++++++++++++++ 1 file changed, 56 insertions(+) create mode 100644 ko-KR/src/guide/migration/keycode-modifiers.md diff --git a/ko-KR/src/guide/migration/keycode-modifiers.md b/ko-KR/src/guide/migration/keycode-modifiers.md new file mode 100644 index 000000000..8402b927c --- /dev/null +++ b/ko-KR/src/guide/migration/keycode-modifiers.md @@ -0,0 +1,56 @@ +--- +badges: +- breaking +--- + +# 키 입력 수식어 + +## 개요 + +변경내용: + +- **주의**: `v-on`에 숫자를 사용한 키 입력 수식어는 더이상 지원되지 않습니다. +- **주의**: `config.keyCodes`는 더이상 지원되지 않습니다. + +## 2.x 구문 + +Vue 2에서는 `v-on` 메서드를 수정하는 방식으로 `키 코드(keyCode)`를 지원했습니다. + +```html + + + + + +``` + +또한, 전역 `config.keyCodes` 옵션을 통해 사용자 정의 별칭을 설정할 수 있었습니다. + +```js +Vue.config.keyCodes = { + f1: 112 +} +``` + +```html + + + + + +``` + +## 3.x 구문 + +[`KeyboardEvent.keyCode`를 더이상 사용하지 않기로 한 후,](https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent/keyCode) Vue 3에서 이 기능을 유지하는 것은 의미 없는 일이 되었습니다. 이에 따라 수식어로 사용하고 싶은 키에 케밥 케이스(kebab-case) 형식 키 이름을 사용하기를 권장합니다. + +```html + + +``` + +즉, `config.keyCodes` 옵션 역시 사용되지 않으며, 더이상 관련 내용을 지원하지 않을 것임을 의미합니다. + +## 마이그레이션 방법 + +코드 전반에 `키 코드(keyCode)`를 사용하는 경우, 케밥 케이스(kebab-case) 형식 키 이름으로 변환하기를 권장합니다. From 5a8f0f9fdc5d6ef2300759a54ca4123366aa207e Mon Sep 17 00:00:00 2001 From: Haneul Cho Date: Mon, 24 Aug 2020 13:21:04 +0000 Subject: [PATCH 028/416] Translate conditional.md via GitLocalize --- ko-KR/src/guide/conditional.md | 92 ++++++++++++++++++++++++++++++++++ 1 file changed, 92 insertions(+) create mode 100644 ko-KR/src/guide/conditional.md diff --git a/ko-KR/src/guide/conditional.md b/ko-KR/src/guide/conditional.md new file mode 100644 index 000000000..4d817cad8 --- /dev/null +++ b/ko-KR/src/guide/conditional.md @@ -0,0 +1,92 @@ +# 조건부 렌더링 + +## `v-if` + +`v-if` 디렉티브는 조건에 따라 블록을 렌더링할 때 사용합니다. 블록은 디렉티브의 표현식이 true 값을 반환할 때만 렌더링됩니다. + +```html +

    Vue is awesome!

    +``` + +`v-else`와 함께 “else 블록”을 추가하는 것도 가능합니다. + +```html +

    Vue is awesome!

    +

    Oh no 😢

    +``` + +### `