├── .all-contributorsrc ├── .github ├── CODEOWNERS ├── CODE_OF_CONDUCT.md ├── DOC_CONTRIBUTION_GUIDE.md ├── HOW_TO_CONTRIBUTE.md ├── MARKDOWN_GUIDE.md ├── PR_COMMIT_CONVENTION.md ├── WHAT_TO_CONTRIBUTE.md ├── pull_request_template.md └── workflows │ ├── auto-deployment.yml │ └── greetings.yml ├── .gitignore ├── .husky └── pre-commit ├── .nvmrc ├── .prettierrc ├── .yarn └── releases │ └── yarn-1.22.19.cjs ├── .yarnrc.yml ├── LICENSE ├── README.md ├── commands ├── README.md └── add-contributor.sh ├── deploy.sh ├── docs ├── .gitignore ├── .vuepress │ ├── aliases.config.js │ ├── components │ │ └── UserLogin.vue │ ├── config.js │ ├── enhanceApp.js │ ├── plugins │ │ └── custom-back-to-top │ │ │ ├── BackToTop.vue │ │ │ ├── enhanceAppFile.js │ │ │ └── index.js │ ├── public │ │ ├── favicon.ico │ │ ├── images │ │ │ ├── cli-service-inspect-output.png │ │ │ ├── cli-service-webpack.png │ │ │ ├── component-communication.png │ │ │ ├── component.png │ │ │ ├── console-instance.png │ │ │ ├── cors-error.png │ │ │ ├── cors.png │ │ │ ├── deploy-folder-structure.png │ │ │ ├── icons │ │ │ │ ├── 120x.png │ │ │ │ ├── 128x.png │ │ │ │ ├── 144x.png │ │ │ │ ├── 152x.png │ │ │ │ ├── 167x.png │ │ │ │ ├── 180x.png │ │ │ │ ├── 192x.png │ │ │ │ ├── 384x.png │ │ │ │ ├── 512x.png │ │ │ │ ├── 72x.png │ │ │ │ └── 96x.png │ │ │ ├── lifecycle.png │ │ │ ├── test │ │ │ │ ├── cli-option-1.png │ │ │ │ ├── cli-option-2.png │ │ │ │ ├── cli-option-3.png │ │ │ │ ├── cli-option-4.png │ │ │ │ ├── jest-parsing-error.png │ │ │ │ ├── test-result.png │ │ │ │ ├── vue-cli-preset-setup.png │ │ │ │ └── vue-cli-test-setup.png │ │ │ ├── todo-app-todo-control.png │ │ │ ├── transition-flow.png │ │ │ ├── ts-error.png │ │ │ ├── ts-extend-error.png │ │ │ ├── ts-presets.png │ │ │ ├── vue-component-testing.png │ │ │ ├── vuex-concept.png │ │ │ ├── vuex-flow.png │ │ │ └── web-dev-flow.png │ │ ├── logo.png │ │ └── manifest.json │ └── styles │ │ ├── index.styl │ │ └── palette.styl ├── README.md ├── advanced │ ├── code-splitting.md │ ├── folder-structure.md │ ├── navigation-guard.md │ └── transition.md ├── composition │ ├── computed.md │ ├── event-emit.md │ ├── img │ │ └── afterToRefs.png │ ├── lifecycle.md │ ├── props.md │ ├── script-setup.md │ └── watch.md ├── d3 │ ├── README.md │ ├── d3.md │ ├── images │ │ ├── d3-line-axis.png │ │ ├── d3-line-path.png │ │ └── tutorial-npm-vue.png │ ├── tutorial.md │ └── vue-with-d3.md ├── deploy │ ├── cli3-rules.md │ ├── env-setup.md │ └── intro.md ├── design │ ├── pattern1.md │ ├── pattern2.md │ ├── pattern3.md │ ├── pattern4.md │ └── pattern5.md ├── es6+ │ ├── async-await.md │ ├── class.md │ ├── const-let.md │ ├── default-parameter.md │ ├── destructuring.md │ ├── enhanced-object-literals.md │ ├── fat-arrow.md │ ├── modules.md │ ├── nullish-coalescing-operator.md │ ├── optional-chaning.md │ ├── promise.md │ ├── spread-operator.md │ └── template-literal.md ├── format │ ├── cli-questions.png │ ├── format-on-save.png │ ├── img │ │ └── husky-prettier-error.png │ ├── official.md │ └── prettier.md ├── front-dev.md ├── index.html ├── js │ ├── array.md │ ├── closure.md │ ├── collection.md │ ├── condition.md │ ├── function.md │ ├── loop.md │ ├── number.md │ ├── object.md │ ├── operator.md │ ├── prototype.md │ ├── scope.md │ ├── string.md │ ├── this.md │ └── variable.md ├── legacy │ ├── chart.md │ ├── datepicker.md │ ├── form.md │ └── jquery-to-vue.md ├── nuxt │ ├── automatic-routing.md │ ├── data-fetching.md │ ├── deployment.md │ ├── folder-structure.md │ ├── images │ │ ├── age-of-next.png │ │ ├── app-mode.png │ │ ├── axios-options.png │ │ ├── comp-commu.png │ │ ├── comp.png │ │ ├── csr-result.gif │ │ ├── document-access-error.png │ │ ├── fetch-page-navigation.gif │ │ ├── fetch-ssr-rendering.gif │ │ ├── folder.png │ │ ├── install-axios.png │ │ ├── nuxt-folder-structure.png │ │ ├── nuxt-js-operation-flow.png │ │ ├── nuxt-routing.gif │ │ ├── nuxt.png │ │ ├── og-tag.png │ │ ├── page-folder.png │ │ ├── prefetching.gif │ │ ├── rendering-mode.png │ │ ├── ssr-vs-csr.png │ │ └── store-index.png │ ├── intro.md │ ├── layouts.md │ ├── lifecycle.md │ ├── meta-tags.md │ ├── middleware.md │ ├── nuxt-axios.md │ ├── nuxt-config.md │ ├── ssr.md │ ├── store.md │ └── universal-mode.md ├── nuxt3 │ ├── data-fetching.md │ └── intro.md ├── package-manager │ └── npm-vs-yarn.md ├── pinia │ ├── actions.md │ ├── getters.md │ ├── intro.md │ ├── state.md │ └── store.md ├── pwa │ ├── cli-pwa-plugin.md │ ├── workbox-caching.md │ └── workbox.md ├── reuse │ ├── composition.md │ ├── mixins-vs-hoc.md │ ├── mixins.md │ ├── plugins.md │ ├── scoped-slot.md │ ├── slots.md │ └── v-slot.md ├── syntax │ ├── computed.md │ ├── filters.md │ ├── form.md │ ├── methods.md │ └── watch.md ├── testing │ ├── api.md │ ├── component-tutorial-1.md │ ├── coverage.md │ ├── getting-started.md │ ├── jest-api.md │ ├── jest-testing.md │ ├── overview.md │ ├── snapshots.md │ ├── tutorial-todo-app.md │ └── vue-test-util.md ├── textbook.md ├── ts │ ├── getting-started.md │ ├── images │ │ ├── store-infer-error.png │ │ ├── store-infer.gif │ │ └── vue-ts.png │ ├── intro.md │ ├── pdecorator.md │ ├── refs.md │ ├── vuex.md │ └── with-vue.md ├── vite │ ├── images │ │ └── import-error.png │ └── intro.md ├── vue │ ├── axios.md │ ├── cli.md │ ├── components-communication.md │ ├── components.md │ ├── event-emit.md │ ├── instance.md │ ├── life-cycle.md │ ├── props.md │ ├── router.md │ ├── sfc.md │ └── template.md ├── vue3.md ├── vuepress │ └── learning-note.md ├── vuex │ ├── actions.md │ ├── concept.md │ ├── getters.md │ ├── helper.md │ ├── modules.md │ ├── mutations.md │ ├── state-vs-data.md │ └── state.md └── webpack │ └── project-setup.md ├── efe.sh ├── img ├── filter-googling.png ├── issue-sample.png ├── prototype_001.png ├── prototype_002.png ├── prototype_003.png ├── schedule.png └── vite-network.png ├── package-lock.json ├── package.json └── vercel.json /.github/CODEOWNERS: -------------------------------------------------------------------------------- 1 | # Global Owners 2 | * @joshua1988 @amorfati0310 @jm-chong @daep93 -------------------------------------------------------------------------------- /.github/CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | ## 행동 강령(Code of Conduct) 2 | 3 | 이 프로젝트에 기여하는 분들은 다음 규칙을 준수해야 합니다. 4 | 5 | - 프로젝트 참여 인원에 대한 상호 존중. 비방 자제. 6 | - 종교, 성차별 등 상대방에 대한 인격 모독 금지. 7 | 8 | 위 사항을 준수하지 않는 경우에는 언제든지 프로젝트 관리자에 의해 경고 없이 관련 PR, Issue, 댓글이 삭제될 수 있습니다. -------------------------------------------------------------------------------- /.github/DOC_CONTRIBUTION_GUIDE.md: -------------------------------------------------------------------------------- 1 | # 문서 작성 가이드 2 | 3 | Cracking Vue.js 사이트 문서 작성 가이드입니다. 4 | 5 | ## 문서 작성 전 6 | 7 | 작성하고자 하는 주제나 개념에 대해 충분히 조사합니다. 예를 들어, 자바스크립트의 .filter() 메서드에 대한 사용법 가이드를 작성한다고 하면 최소 공식 스펙 문서인 [MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/filter)과 잘 정리되어 있는 [JavaScript Info](https://javascript.info/array-methods)를 보고 실제 사례 코드나 튜토리얼도 같이 찾아봅니다. 실제 사례나 튜토리얼을 찾아보기 위해서는 구글에 대략 *js filter tutorials* 이런 형식으로 검색하여 잘 정돈된 사이트의 내용을 참고합니다. 8 | 9 | ![filter googling](./../img/filter-googling.png) 10 | 11 | 문서를 잘 작성하는 방법의 시작은 해당 내용을 얼마나 깊이 이해하고 사례를 살펴봤는가입니다. 12 | 13 | ## 문서 작성 중 14 | 15 | 문서 작성을 시작할 때 먼저 목차를 구성합니다. 보통은 아래와 같은 형태로 글을 전개해 나가는 것을 추천드립니다. 앞에서 예시로 든 자바스크립트 .filter() 메서드를 보겠습니다. 16 | 17 | - filter()의 정의 18 | - filter()를 가장 쉽게 이해할 수 있는 하나의 예제와 설명 19 | - filter()를 적용하면 좋은 곳들 20 | - filter()를 사용했을 때와 사용하지 않고 구현한 코드의 차이점 21 | - 기타 22 | 23 | 특정 개념과 주제를 설명할 때는 해당 개념에 대해 한 줄 정의를 내리는 습관을 들이시는 걸 추천드립니다. 한 줄 정의가 어려운 경우에는 보통 개념을 정확히 이해하지 못했거나 관련 내용을 충분히 학습하지 못했다고 볼 수 있습니다. 따라서 문서 작성 전으로 돌아가 관련 내용을 충분히 숙지합니다. 그리고 코드의 경우에는 보통 문서를 작성하기 전에 자기 스스로 코드를 구현해 보고 에러를 부딪혀 보면서 관련 내용을 더 깊이 이해하려고 하면 좋은 문서가 나온다고 생각합니다. 24 | 25 | ## 문서 작성 후 26 | 27 | 문서를 다 작성하고 나면 최소 2~3번 퇴고하시는 걸 추천드립니다. 문서를 작성하고 PR을 보내기 전까지 내가 작성한 글을 PC와 모바일에서 각각 최소 2번씩 읽어보면 글의 흐름이 부자연스럽거나 표현이 아쉬운 부분이 보이기 마련입니다. 해당 습관을 들이기까지는 시간이 꽤 걸리겠지만 반복해서 익숙해 지시면 더 퇴고 시간이 줄어들고 글의 흐름도 더 자연스러워집니다. 28 | 29 | 그리고 퇴고하는 중간에 더 자연스러운 글을 만들기 위해 아래 맞춤법 검사기를 이용하여 글을 다듬는 걸 추천합니다. 30 | 31 | - [부산대 맞춤법 검사기](https://speller.cs.pusan.ac.kr/) 32 | - [네이버 맞춤법 검사기](https://search.naver.com/search.naver?where=nexearch&sm=top_hty&fbm=0&ie=utf8&query=%EB%A7%9E%EC%B6%A4%EB%B2%95+%EA%B2%80%EC%82%AC%EA%B8%B0) 33 | 34 | 문서 작성에 들이시는 시간 못지않게 문서를 정리하는 시간도 중요합니다. 35 | 36 | --- 37 | 38 | 그외 문서 작성에 필요한 컨벤션을 소개합니다. 39 | 40 | ## 외래어 표기 41 | 42 | 가급적 모든 기술 용어는 첫 언급시에 다음과 같이 풀어쓰고 그 이후에는 읽기 쉽게 한글로 기술합니다. 43 | 44 | ex) 45 | 자바스크립트(JavaScript)는 브라우저에서 동작하는 스크립트 언어입니다. 자바스크립트의 .... 46 | 웹팩(Webpack)은 프런트엔드 개발할 때 사용하는 빌드 도구입니다. 웹팩을 이용하여 .... 47 | 48 | ## 인라인 코드 49 | 50 | 문서의 중간에 코드 예시에서 사용한 코드를 가리킬 때는 마크다운 문법의 **``** 문법을 활용합니다. 51 | 52 | ex) 위 코드에서 사용한 변수 `userInfo`는 속성 `name`과 `role`을 갖고 있습니다. 53 | 54 | ## 소스 코드 삽입 55 | 56 | 문서 작성 중 여러 줄의 소스 코드를 삽입할 때는 마크다운 문법의 \``` 를 활용합니다. 삽입하는 소스의 언어를 \``` 의 오른쪽에 기입해 주면 아래와 같이 하이라이팅이 됩니다. 57 | 58 | ex) 59 | 60 | ```html 61 |
html 소스 코드
62 |

굿굿

63 | ``` 64 | 65 | ```js 66 | var a = 10; 67 | a = 20; 68 | ``` 69 | 70 | ## 이미지 71 | 72 | 문서 작성 중간에 이해를 돕는 이미지를 삽입하고 싶은 경우 마크다운 문법의 ```![]()```를 활용합니다. 73 | 74 | ``` 75 | ![이미지 설명](이미지 주소) 76 | ``` 77 | 78 | ## 각주(tip, warning, danger, details) 79 | 80 | 본문 중간에 특정 용어에 대한 부가 설명 또는 팁, 주의 사항을 추가하고 싶을 때는 아래 문법을 활용합니다. 81 | 82 | ``` 83 | :::tip 84 | 뷰의 컴포넌트 구조는 리액트와 유사합니다. 85 | ::: 86 | ``` 87 | 88 | tip, warning, danger, details 여러 레벨로 나뉘기 때문에 해당 내용은 아래 링크를 참고하세요. 89 | 90 | [VuePress Custom Container](https://vuepress.vuejs.org/guide/markdown.html#custom-containers) 91 | 92 | ## 참고 자료 93 | 94 | 참고 자료 링크는 아래와 같이 마크다운 문법을 활용합니다. 95 | 96 | ``` 97 | [웹팩 가이드](https://joshua1988.github.io/webpack-guide) 98 | ``` 99 | -------------------------------------------------------------------------------- /.github/PR_COMMIT_CONVENTION.md: -------------------------------------------------------------------------------- 1 | # PR & Commit 작성 가이드 2 | 3 | ## Commit 작성 가이드 4 | 5 | 커밋 메시지는 해당 변경 분량의 내용을 충분히 담을 수 있도록 간단 명료하게 핵심만 작성합니다. 6 | 7 | ``` 8 | [문서화] 자바스크립트 filter() 가이드 문서 작성 9 | [자료 추가] 필터 동작 방식 관련 이미지 및 링크 삽입 10 | ``` 11 | 12 | 커밋 메시지의 맨 앞에는 항상 `[]` 레이블로 해당 커밋 메시지의 유형을 분류해 줍니다. 예를 들면, `문서화`, `기능 구현`, `소스 추가`, `주석 추가/변경/삭제`, `파일명 변경` 등 13 | 14 | ## PR 작성 가이드 15 | 16 | PR의 제목에도 Commit과 동일하게 레이블을 맨 앞에 표기해 줍니다. 17 | 18 | ``` 19 | [doc] 자바스크립트 filter() 활용 가이드 제작 20 | [tool] 뷰프레스 다국어 플러그인 추가 및 관련 설정 변경 21 | ``` 22 | 23 | 위 레이블은 이슈 생성할 때 선택한 레이블과 동일해야 합니다. 24 | 25 | ![issue-sample](../img/issue-sample.png) 26 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /.github/WHAT_TO_CONTRIBUTE.md: -------------------------------------------------------------------------------- 1 | # 프로젝트에 어떻게 기여할 것인가? 2 | 3 | Cracking Vue.js 프로젝트에 기여할 수 있는 방법은 크게 다음 4가지 입니다. 4 | 5 | - Vue.js 개발 관련 주제 문서화 6 | - 소스 레벨 튜토리얼 제작 및 가이드 제공 7 | - Cracking Vue.js 사이트 툴링 8 | - 국문으로 제작되어 있는 문서의 영문화 9 | 10 | ## Vue.js 개발 관련 주제 문서화 11 | 12 | 현재 Cracking Vue.js 사이트에서 다루고 있는 내용은 다음과 같습니다. 13 | 14 | - 자바스크립트 기초 15 | - 자바스크립트 최신 문법 16 | - Vue.js 기본 개념부터 실용 문법 17 | - Vue.js 테스팅, 타입스크립트, 서버 사이드 렌더링 18 | - Vue CLI를 이용한 프로젝트 생성과 배포, 환경 구축 19 | 20 | 위 주제에서 확장하여 관련 가이드를 추가하셔도 되고 아직 구체적으로 다루고 있지 않은 개념과 새로운 기술에 대한 가이드도 권장합니다. 예를 들어 다음 주제들을 추천합니다. 21 | 22 | - 자바스크립트 23 | - 타입스크립트 24 | - Vue Testing(Unit & E2E) 25 | - Vue Composition(Vue 3) 26 | - Vue 3 with TypeScript 27 | - Vue.js with StoryBook 28 | - Vite 29 | - VuePress 30 | 31 | ## 소스 레벨 튜토리얼 제작 및 가이드 제공 32 | 33 | 소스가 포함된 간단한 형태의 튜토리얼 가이드는 다음과 같이 사이트에 바로 추가하는 것을 추천합니다. 34 | 35 | [Vue.js Slots](https://joshua1988.github.io/vue-camp/reuse/slots.html) 36 | 37 | 하지만 소스로 다루려는 주제의 범위가 크고 시리즈 형태의 연속성을 띠고 있는 경우 아래와 같이 별도의 리포지토리로 제작 후 가이드만 사이트에서 제공하는 것을 추천합니다. 38 | 39 | [vue-test-tutorial](https://github.com/joshua1988/vue-test-tutorial) 40 | 41 | ## Cracking Vue.js 사이트 툴링 42 | 43 | VuePress 기반으로 제작되어 있는 Cracking Vue.js 사이트에 기여할 수 있는 방법은 여러 가지입니다. 44 | 45 | - 사이트 이용자가 더 편하게 문서를 볼 수 있도록 특정 기능을 제공하는 플러그인 조사/제작/추가 46 | - 사이트 컨텐츠 가독성을 높이기 위한 스타일링 & 레이아웃 개선 47 | - 기존 사이트 플러그인 업데이트 및 유지 관리 48 | 49 | 관심 있는 플러그인을 설치하거나 제작 후 팀내 컨벤션을 따라 PR을 요청하시면 됩니다. 50 | 51 | ## 국문으로 제작되어 있는 문서의 영문화 52 | 53 | 현재 사이트의 컨텐츠는 국문으로만 제공됩니다. 특정 문서나 개념을 영문으로 번역하여 제공하고 싶다면 아래 가이드를 참고하여 진행합니다. 54 | 55 | [VuePress i18n](https://vuepress.vuejs.org/guide/i18n.html) -------------------------------------------------------------------------------- /.github/pull_request_template.md: -------------------------------------------------------------------------------- 1 | ## 관련 이슈 2 | 3 | 4 | 5 | ## 요약 6 | 7 | 8 | 9 | ## 리뷰어 10 | 11 | -------------------------------------------------------------------------------- /.github/workflows/auto-deployment.yml: -------------------------------------------------------------------------------- 1 | # This is a basic workflow to help you get started with Actions 2 | 3 | name: Github page deployment on pull request merged 4 | 5 | # Controls when the workflow will run 6 | on: 7 | # Triggers the workflow on push or pull request events but only for the master branch 8 | push: 9 | branches: [ master ] 10 | 11 | # Allows you to run this workflow manually from the Actions tab 12 | workflow_dispatch: 13 | 14 | jobs: 15 | build-and-deploy: 16 | runs-on: ubuntu-latest 17 | 18 | strategy: 19 | matrix: 20 | node-version: [14.19.1] 21 | 22 | steps: 23 | - name: Setup Node.js 24 | uses: actions/setup-node@v3 25 | with: 26 | node-version: ${{ matrix.node-version }} 27 | 28 | - name: Checkout 🛎️ 29 | uses: actions/checkout@v2.3.1 30 | 31 | - name: Install and Build 🔧 # This example project is built using npm and outputs the result to the 'build' folder. Replace with the commands required to build your project, or remove this step entirely if your site is pre-built. 32 | run: | 33 | npm i 34 | npm run build 35 | 36 | - name: Deploy 🚀 37 | uses: JamesIves/github-pages-deploy-action@4.1.4 38 | with: 39 | branch: gh-pages # The branch the action should deploy to. 40 | folder: docs/.vuepress/dist # The folder the action should deploy. 41 | 42 | # A workflow run is made up of one or more jobs that can run sequentially or in parallel 43 | # jobs: 44 | # # This workflow contains a single job called "build" 45 | # build: 46 | # # The type of runner that the job will run on 47 | # runs-on: ubuntu-latest 48 | 49 | # # Steps represent a sequence of tasks that will be executed as part of the job 50 | # steps: 51 | # # Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it 52 | # - uses: actions/checkout@v2 53 | 54 | # # Runs a single command using the runners shell 55 | # - name: Run a one-line script 56 | # run: echo Hello, world! 57 | 58 | # # Runs a set of commands using the runners shell 59 | # - name: Run a multi-line script 60 | # run: | 61 | # echo Add other actions to build, 62 | # echo test, and deploy your project. 63 | -------------------------------------------------------------------------------- /.github/workflows/greetings.yml: -------------------------------------------------------------------------------- 1 | name: Greetings 2 | 3 | on: [pull_request, issues] 4 | 5 | jobs: 6 | greeting: 7 | runs-on: ubuntu-latest 8 | permissions: 9 | issues: write 10 | pull-requests: write 11 | steps: 12 | - uses: actions/first-interaction@v1 13 | with: 14 | repo-token: ${{ secrets.GITHUB_TOKEN }} 15 | issue-message: '프로젝트에 기여해 주셔서 감사합니다. 앞으로도 많은 참여 부탁드려요 :smile: :tada:' 16 | pr-message: '의미있는 첫 번째 PR 정말 감사합니다. 빠른 시간 안에 리뷰 후 피드백 드릴게요. 앞으로도 더 적극적인 컨트리뷰션 기대하겠습니다! :smile: :tada:' 17 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # JetBrains IDE 2 | .idea 3 | 4 | # VS Code 5 | .vscode 6 | 7 | # Build 8 | dist 9 | 10 | # Visual Studio Code 11 | .vs 12 | 13 | # Vue Press 14 | # dist 15 | # docs/.vuepress/dist 16 | 17 | # Logs 18 | logs 19 | *.log 20 | npm-debug.log* 21 | yarn-debug.log* 22 | yarn-error.log* 23 | 24 | # Runtime data 25 | pids 26 | *.pid 27 | *.seed 28 | *.pid.lock 29 | 30 | # Directory for instrumented libs generated by jscoverage/JSCover 31 | lib-cov 32 | 33 | # Coverage directory used by tools like istanbul 34 | coverage 35 | 36 | # nyc test coverage 37 | .nyc_output 38 | 39 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) 40 | .grunt 41 | 42 | # Bower dependency directory (https://bower.io/) 43 | bower_components 44 | 45 | # node-waf configuration 46 | .lock-wscript 47 | 48 | # Compiled binary addons (https://nodejs.org/api/addons.html) 49 | build/Release 50 | 51 | # Dependency directories 52 | node_modules/ 53 | jspm_packages/ 54 | 55 | # TypeScript v1 declaration files 56 | typings/ 57 | 58 | # Optional npm cache directory 59 | .npm 60 | 61 | # Optional eslint cache 62 | .eslintcache 63 | 64 | # Optional REPL history 65 | .node_repl_history 66 | 67 | # Output of 'npm pack' 68 | *.tgz 69 | 70 | # Yarn Integrity file 71 | .yarn-integrity 72 | 73 | # dotenv environment variables file 74 | .env 75 | 76 | # next.js build output 77 | .next 78 | 79 | .DS_Store 80 | 81 | .vercel 82 | -------------------------------------------------------------------------------- /.husky/pre-commit: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | . "$(dirname "$0")/_/husky.sh" 3 | 4 | yarn lint-front 5 | -------------------------------------------------------------------------------- /.nvmrc: -------------------------------------------------------------------------------- 1 | 14.19.1 -------------------------------------------------------------------------------- /.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "singleQuote": true, 3 | "semi": true, 4 | "useTabs": false, 5 | "tabWidth": 2, 6 | "trailingComma": "all", 7 | "printWidth": 120, 8 | "parser": "babel", 9 | "bracketSpacing": true, 10 | "arrowParens": "avoid", 11 | "overrides": [ 12 | { 13 | "files": ".prettierrc", 14 | "options": { 15 | "parser": "json" 16 | } 17 | }, 18 | { 19 | "files": "*.md", 20 | "options": { 21 | "parser": "markdown" 22 | } 23 | } 24 | ] 25 | } 26 | -------------------------------------------------------------------------------- /.yarnrc.yml: -------------------------------------------------------------------------------- 1 | yarnPath: .yarn/releases/yarn-1.22.19.cjs 2 | -------------------------------------------------------------------------------- /commands/README.md: -------------------------------------------------------------------------------- 1 | ## 명령어 안내 2 | 3 | Cracking Vue.js 사이트를 로컬에서 실행하기 위한 명령어와 배포 명령어를 안내합니다. 4 | 5 | - 프로젝트 로컬 실행 명령어 : `sh start.sh` 6 | - 프로젝트 배포 명령어 : `sh deploy.sh` -------------------------------------------------------------------------------- /commands/add-contributor.sh: -------------------------------------------------------------------------------- 1 | yarn insert -------------------------------------------------------------------------------- /deploy.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | 3 | # abort on errors 4 | set -e 5 | 6 | # build commands 7 | npm run build 8 | 9 | # navigate into the build output directory 10 | cd ../docs/.vuepress/dist 11 | 12 | git init 13 | git add -A 14 | git commit -m 'deploy with vuepress script' 15 | git push -f https://github.com/joshua1988/vue-camp.git main:gh-pages 16 | 17 | cd - -------------------------------------------------------------------------------- /docs/.gitignore: -------------------------------------------------------------------------------- 1 | ./vuepress/dist -------------------------------------------------------------------------------- /docs/.vuepress/aliases.config.js: -------------------------------------------------------------------------------- 1 | const path = require('path') 2 | 3 | function resolveSrc(_path) { 4 | return path.join(__dirname, _path) 5 | } 6 | 7 | const aliases = { 8 | '@store': '.vuepress/store.js', 9 | } 10 | 11 | module.exports = { 12 | webpack: {}, 13 | } 14 | 15 | for (const alias in aliases) { 16 | module.exports.webpack[alias] = resolveSrc(aliases[alias]) 17 | } -------------------------------------------------------------------------------- /docs/.vuepress/components/UserLogin.vue: -------------------------------------------------------------------------------- 1 | 12 | 13 | 74 | 75 | 98 | -------------------------------------------------------------------------------- /docs/.vuepress/enhanceApp.js: -------------------------------------------------------------------------------- 1 | export default ({ 2 | Vue, 3 | router, 4 | options, 5 | siteData 6 | }) => { 7 | // router.beforeEach((to, from, next) => { 8 | // console.log(router.options); 9 | 10 | // if (to.path === '/' || to.path === '/textbook.html') { 11 | // next(); 12 | // } else { 13 | // if (router.options.auth) { 14 | // next(); 15 | // } else { 16 | // alert('등록된 수강생 아이디로만 접근할 수 있습니다.'); 17 | // } 18 | // } 19 | // }) 20 | } 21 | -------------------------------------------------------------------------------- /docs/.vuepress/plugins/custom-back-to-top/BackToTop.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 33 | -------------------------------------------------------------------------------- /docs/.vuepress/plugins/custom-back-to-top/enhanceAppFile.js: -------------------------------------------------------------------------------- 1 | import BackToTop from './BackToTop' 2 | 3 | export default ({ Vue }) => { 4 | // eslint-disable-next-line vue/match-component-file-name 5 | Vue.component('BackToTop', BackToTop) 6 | } 7 | -------------------------------------------------------------------------------- /docs/.vuepress/plugins/custom-back-to-top/index.js: -------------------------------------------------------------------------------- 1 | const { path } = require('@vuepress/shared-utils') 2 | 3 | module.exports = { 4 | enhanceAppFiles: [ 5 | path.resolve(__dirname, 'enhanceAppFile.js') 6 | ], 7 | 8 | globalUIComponents: 'BackToTop' 9 | } 10 | -------------------------------------------------------------------------------- /docs/.vuepress/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/joshua1988/vue-camp/1d2b5ed08f37e891e5dd2c762a9cc25d2351a9dc/docs/.vuepress/public/favicon.ico -------------------------------------------------------------------------------- /docs/.vuepress/public/images/cli-service-inspect-output.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/joshua1988/vue-camp/1d2b5ed08f37e891e5dd2c762a9cc25d2351a9dc/docs/.vuepress/public/images/cli-service-inspect-output.png -------------------------------------------------------------------------------- /docs/.vuepress/public/images/cli-service-webpack.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/joshua1988/vue-camp/1d2b5ed08f37e891e5dd2c762a9cc25d2351a9dc/docs/.vuepress/public/images/cli-service-webpack.png -------------------------------------------------------------------------------- /docs/.vuepress/public/images/component-communication.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/joshua1988/vue-camp/1d2b5ed08f37e891e5dd2c762a9cc25d2351a9dc/docs/.vuepress/public/images/component-communication.png -------------------------------------------------------------------------------- /docs/.vuepress/public/images/component.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/joshua1988/vue-camp/1d2b5ed08f37e891e5dd2c762a9cc25d2351a9dc/docs/.vuepress/public/images/component.png -------------------------------------------------------------------------------- /docs/.vuepress/public/images/console-instance.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/joshua1988/vue-camp/1d2b5ed08f37e891e5dd2c762a9cc25d2351a9dc/docs/.vuepress/public/images/console-instance.png -------------------------------------------------------------------------------- /docs/.vuepress/public/images/cors-error.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/joshua1988/vue-camp/1d2b5ed08f37e891e5dd2c762a9cc25d2351a9dc/docs/.vuepress/public/images/cors-error.png -------------------------------------------------------------------------------- /docs/.vuepress/public/images/cors.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/joshua1988/vue-camp/1d2b5ed08f37e891e5dd2c762a9cc25d2351a9dc/docs/.vuepress/public/images/cors.png -------------------------------------------------------------------------------- /docs/.vuepress/public/images/deploy-folder-structure.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/joshua1988/vue-camp/1d2b5ed08f37e891e5dd2c762a9cc25d2351a9dc/docs/.vuepress/public/images/deploy-folder-structure.png -------------------------------------------------------------------------------- /docs/.vuepress/public/images/icons/120x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/joshua1988/vue-camp/1d2b5ed08f37e891e5dd2c762a9cc25d2351a9dc/docs/.vuepress/public/images/icons/120x.png -------------------------------------------------------------------------------- /docs/.vuepress/public/images/icons/128x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/joshua1988/vue-camp/1d2b5ed08f37e891e5dd2c762a9cc25d2351a9dc/docs/.vuepress/public/images/icons/128x.png -------------------------------------------------------------------------------- /docs/.vuepress/public/images/icons/144x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/joshua1988/vue-camp/1d2b5ed08f37e891e5dd2c762a9cc25d2351a9dc/docs/.vuepress/public/images/icons/144x.png -------------------------------------------------------------------------------- /docs/.vuepress/public/images/icons/152x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/joshua1988/vue-camp/1d2b5ed08f37e891e5dd2c762a9cc25d2351a9dc/docs/.vuepress/public/images/icons/152x.png -------------------------------------------------------------------------------- /docs/.vuepress/public/images/icons/167x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/joshua1988/vue-camp/1d2b5ed08f37e891e5dd2c762a9cc25d2351a9dc/docs/.vuepress/public/images/icons/167x.png -------------------------------------------------------------------------------- /docs/.vuepress/public/images/icons/180x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/joshua1988/vue-camp/1d2b5ed08f37e891e5dd2c762a9cc25d2351a9dc/docs/.vuepress/public/images/icons/180x.png -------------------------------------------------------------------------------- /docs/.vuepress/public/images/icons/192x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/joshua1988/vue-camp/1d2b5ed08f37e891e5dd2c762a9cc25d2351a9dc/docs/.vuepress/public/images/icons/192x.png -------------------------------------------------------------------------------- /docs/.vuepress/public/images/icons/384x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/joshua1988/vue-camp/1d2b5ed08f37e891e5dd2c762a9cc25d2351a9dc/docs/.vuepress/public/images/icons/384x.png -------------------------------------------------------------------------------- /docs/.vuepress/public/images/icons/512x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/joshua1988/vue-camp/1d2b5ed08f37e891e5dd2c762a9cc25d2351a9dc/docs/.vuepress/public/images/icons/512x.png -------------------------------------------------------------------------------- /docs/.vuepress/public/images/icons/72x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/joshua1988/vue-camp/1d2b5ed08f37e891e5dd2c762a9cc25d2351a9dc/docs/.vuepress/public/images/icons/72x.png -------------------------------------------------------------------------------- /docs/.vuepress/public/images/icons/96x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/joshua1988/vue-camp/1d2b5ed08f37e891e5dd2c762a9cc25d2351a9dc/docs/.vuepress/public/images/icons/96x.png -------------------------------------------------------------------------------- /docs/.vuepress/public/images/lifecycle.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/joshua1988/vue-camp/1d2b5ed08f37e891e5dd2c762a9cc25d2351a9dc/docs/.vuepress/public/images/lifecycle.png -------------------------------------------------------------------------------- /docs/.vuepress/public/images/test/cli-option-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/joshua1988/vue-camp/1d2b5ed08f37e891e5dd2c762a9cc25d2351a9dc/docs/.vuepress/public/images/test/cli-option-1.png -------------------------------------------------------------------------------- /docs/.vuepress/public/images/test/cli-option-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/joshua1988/vue-camp/1d2b5ed08f37e891e5dd2c762a9cc25d2351a9dc/docs/.vuepress/public/images/test/cli-option-2.png -------------------------------------------------------------------------------- /docs/.vuepress/public/images/test/cli-option-3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/joshua1988/vue-camp/1d2b5ed08f37e891e5dd2c762a9cc25d2351a9dc/docs/.vuepress/public/images/test/cli-option-3.png -------------------------------------------------------------------------------- /docs/.vuepress/public/images/test/cli-option-4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/joshua1988/vue-camp/1d2b5ed08f37e891e5dd2c762a9cc25d2351a9dc/docs/.vuepress/public/images/test/cli-option-4.png -------------------------------------------------------------------------------- /docs/.vuepress/public/images/test/jest-parsing-error.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/joshua1988/vue-camp/1d2b5ed08f37e891e5dd2c762a9cc25d2351a9dc/docs/.vuepress/public/images/test/jest-parsing-error.png -------------------------------------------------------------------------------- /docs/.vuepress/public/images/test/test-result.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/joshua1988/vue-camp/1d2b5ed08f37e891e5dd2c762a9cc25d2351a9dc/docs/.vuepress/public/images/test/test-result.png -------------------------------------------------------------------------------- /docs/.vuepress/public/images/test/vue-cli-preset-setup.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/joshua1988/vue-camp/1d2b5ed08f37e891e5dd2c762a9cc25d2351a9dc/docs/.vuepress/public/images/test/vue-cli-preset-setup.png -------------------------------------------------------------------------------- /docs/.vuepress/public/images/test/vue-cli-test-setup.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/joshua1988/vue-camp/1d2b5ed08f37e891e5dd2c762a9cc25d2351a9dc/docs/.vuepress/public/images/test/vue-cli-test-setup.png -------------------------------------------------------------------------------- /docs/.vuepress/public/images/todo-app-todo-control.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/joshua1988/vue-camp/1d2b5ed08f37e891e5dd2c762a9cc25d2351a9dc/docs/.vuepress/public/images/todo-app-todo-control.png -------------------------------------------------------------------------------- /docs/.vuepress/public/images/transition-flow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/joshua1988/vue-camp/1d2b5ed08f37e891e5dd2c762a9cc25d2351a9dc/docs/.vuepress/public/images/transition-flow.png -------------------------------------------------------------------------------- /docs/.vuepress/public/images/ts-error.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/joshua1988/vue-camp/1d2b5ed08f37e891e5dd2c762a9cc25d2351a9dc/docs/.vuepress/public/images/ts-error.png -------------------------------------------------------------------------------- /docs/.vuepress/public/images/ts-extend-error.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/joshua1988/vue-camp/1d2b5ed08f37e891e5dd2c762a9cc25d2351a9dc/docs/.vuepress/public/images/ts-extend-error.png -------------------------------------------------------------------------------- /docs/.vuepress/public/images/ts-presets.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/joshua1988/vue-camp/1d2b5ed08f37e891e5dd2c762a9cc25d2351a9dc/docs/.vuepress/public/images/ts-presets.png -------------------------------------------------------------------------------- /docs/.vuepress/public/images/vue-component-testing.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/joshua1988/vue-camp/1d2b5ed08f37e891e5dd2c762a9cc25d2351a9dc/docs/.vuepress/public/images/vue-component-testing.png -------------------------------------------------------------------------------- /docs/.vuepress/public/images/vuex-concept.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/joshua1988/vue-camp/1d2b5ed08f37e891e5dd2c762a9cc25d2351a9dc/docs/.vuepress/public/images/vuex-concept.png -------------------------------------------------------------------------------- /docs/.vuepress/public/images/vuex-flow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/joshua1988/vue-camp/1d2b5ed08f37e891e5dd2c762a9cc25d2351a9dc/docs/.vuepress/public/images/vuex-flow.png -------------------------------------------------------------------------------- /docs/.vuepress/public/images/web-dev-flow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/joshua1988/vue-camp/1d2b5ed08f37e891e5dd2c762a9cc25d2351a9dc/docs/.vuepress/public/images/web-dev-flow.png -------------------------------------------------------------------------------- /docs/.vuepress/public/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/joshua1988/vue-camp/1d2b5ed08f37e891e5dd2c762a9cc25d2351a9dc/docs/.vuepress/public/logo.png -------------------------------------------------------------------------------- /docs/.vuepress/public/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "short_name": "Cracking Vue.js", 3 | "name": "Cracking Vue.js", 4 | "icons": [ 5 | { 6 | "src": "images/icons/72x.png", 7 | "type": "image/png", 8 | "sizes": "72x72" 9 | }, 10 | { 11 | "src": "images/icons/96x.png", 12 | "type": "image/png", 13 | "sizes": "96x96" 14 | }, 15 | { 16 | "src": "images/icons/120x.png", 17 | "type": "image/png", 18 | "sizes": "120x120" 19 | }, 20 | { 21 | "src": "images/icons/128x.png", 22 | "type": "image/png", 23 | "sizes": "128x128" 24 | }, 25 | { 26 | "src": "images/icons/144x.png", 27 | "type": "image/png", 28 | "sizes": "144x144" 29 | }, 30 | { 31 | "src": "images/icons/152x.png", 32 | "type": "image/png", 33 | "sizes": "152x152" 34 | }, 35 | { 36 | "src": "images/icons/167x.png", 37 | "type": "image/png", 38 | "sizes": "167x167" 39 | }, 40 | { 41 | "src": "images/icons/180x.png", 42 | "type": "image/png", 43 | "sizes": "180x180" 44 | }, 45 | { 46 | "src": "images/icons/192x.png", 47 | "type": "image/png", 48 | "sizes": "192x192" 49 | }, 50 | { 51 | "src": "images/icons/384x.png", 52 | "type": "image/png", 53 | "sizes": "384x384" 54 | }, 55 | { 56 | "src": "images/icons/512x.png", 57 | "type": "image/png", 58 | "sizes": "512x512" 59 | } 60 | ], 61 | "theme_color": "#3eaf7c", 62 | "background_color": "#fcfefe", 63 | "display": "standalone", 64 | "start_url": "/vue-camp/" 65 | } -------------------------------------------------------------------------------- /docs/.vuepress/styles/index.styl: -------------------------------------------------------------------------------- 1 | pre .code-copy { 2 | margin-top: -0.85rem; 3 | } 4 | 5 | @media (max-width: 768px) 6 | .theme-code-group__nav 7 | margin-left: -24px 8 | margin-right: -24px -------------------------------------------------------------------------------- /docs/.vuepress/styles/palette.styl: -------------------------------------------------------------------------------- 1 | $readingBgColor = transparent 2 | $readingZIndex = 1000 3 | $readingSize = 4px 4 | $readingProgressImage = none 5 | -------------------------------------------------------------------------------- /docs/README.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Cracking Vue.js 3 | lang: en-US 4 | home: true 5 | heroImage: logo.png 6 | actionText: Get Started → 7 | actionLink: /textbook 8 | # features: 9 | # - title: Simplicity First 10 | # details: Minimal setup with markdown-centered project structure helps you focus on writing. 11 | # - title: Vue-Powered 12 | # details: Enjoy the dev experience of Vue + webpack, use Vue components in markdown, and develop custom themes with Vue. 13 | # - title: Performant 14 | # details: VuePress generates pre-rendered static HTML for each page, and runs as an SPA once a page is loaded. 15 | footer: MIT Licensed | Copyright © 2018-present Captain Pangyo 16 | --- -------------------------------------------------------------------------------- /docs/advanced/code-splitting.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Code Splitting 3 | --- 4 | 5 | # 코드 분할 6 | 7 | 코드 분할(Code Splitting)은 싱글 페이지 애플리케이션의 성능을 향상시키는 방법입니다. 싱글 페이지 애플리케이션(Single Page Application)은 초기 실행시에 필요한 웹 자원을 모두 다운 받는 특징이 있습니다. 코드 분할을 활용하게 되면 초기 로딩시에 모든 웹 자원을 다운받지 않고 필요한 시점에 다운 받아 성능 상의 이점이 생깁니다. 참고로 뷰에서 코드 분할이 가능한 이유는 뷰의 [비동기 컴포넌트 로딩](https://vuejs.org/v2/guide/components-dynamic-async.html#Async-Components)과 웹팩의 [코드 스플리팅 기술](https://webpack.js.org/guides/code-splitting/) 덕택입니다. 8 | 9 | ## 개발 환경 조건 10 | 11 | 다만 지연된 로딩(Lazy Loading) 방법을 적용하기 위해서는 아래와 같은 개발 환경을 갖고 있어야 합니다. 12 | 13 | 1. 싱글 파일 컴포넌트 체계 (.vue) 14 | 2. 웹팩 - 모듈 번들러 (2.x 이상) 15 | 3. 바벨 [Syntax-dynamic-import 플러그인](https://babeljs.io/docs/plugins/syntax-dynamic-import/) 16 | 17 | ### 바벨 Syntax-dynamic-import 설치 방법 18 | 19 | 뷰 CLI로 생성한 경우에는 이미 1번과 2번을 만족하고 계실테지만 3번의 경우에는 별도의 설치가 필요합니다. 20 | 바벨 Syntax-dynamic-import 플러그인 설치는 아래의 절차를 따릅니다. 21 | 22 | 1. [syntax-dynamic-import 플러그인](https://babeljs.io/docs/plugins/syntax-dynamic-import/) 설치 23 | 24 | ```bash 25 | npm install --save-dev babel-plugin-syntax-dynamic-import 26 | ``` 27 | 28 | 2. `.babelrc` 파일에 아래와 같이 플러그인 설정 추가 29 | 30 | ```json 31 | { 32 | "plugins": ["syntax-dynamic-import"] 33 | } 34 | ``` 35 | 36 | ## 라우터의 코드 분할 문법 37 | 38 | 싱글 페이지 애플리케이션에서 뷰 라우터를 사용할 때 라우팅 별로 코드를 분할하는 방법은 아래와 같습니다. 39 | 40 | ```js 41 | { 42 | path: 'url 이름', 43 | component: () => import('컴포넌트 이름') 44 | } 45 | ``` 46 | 47 | 위와 같은 방법을 지연된 로딩(Lazy Loading)이라고 합니다. 이는 애플리케이션 규모가 커져 싱글 페이지 애플리케이션의 초기 화면 로딩 시간을 줄일 때 사용하는 방법입니다. 왜냐면 화면이 10개인 웹 앱이 있는데 애플리케이션을 처음 시작했을 때 쓰지도 않을 나머지 화면 9개를 다 불러오는 것 보다는 48 | 특정 화면으로 이동할 때마다 해당 화면의 내용을 추가적으로 불러오는 것이 애플리케이션 로딩 속도 면에서 더 효율적이기 때문입니다. 49 | 50 | 51 | 52 | 위 환경을 구성하고 나면 아래와 같이 특정 URL에 따른 코드 분할이 가능해집니다. 53 | 54 | ```js 55 | const routes = [ 56 | { 57 | path: '/login', 58 | name: 'login', 59 | component: () => import('./LoginPage.vue') 60 | }, 61 | { 62 | path: '/main', 63 | name: 'main', 64 | component: () => import('./MainPage.vue') 65 | }, 66 | ]; 67 | 68 | new VueRouter({ 69 | mode: 'history', 70 | routes: routes, 71 | }); 72 | ``` -------------------------------------------------------------------------------- /docs/advanced/folder-structure.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Vue Folder Structure 3 | --- 4 | 5 | # 뷰 프로젝트 폴더 구조 6 | 7 | 뷰의 장점 중 하나는 빠른 프토토 타이핑이 가능하다는 점입니다. 뷰 CLI로 프로젝트를 생성하고 나면 npm으로 원하는 기능들을 빠르게 확장해 나갈 수 있습니다. 8 | 9 | 이번 챕터에서는 복잡해진 프로젝트 폴더 구조를 효율적으로 관리하는 방법에 대해서 알아보겠습니다. 철저히 저의 개인적인 의견이 반영된 폴더 구조이기 때문에 참고만 하시고 필요한 것만 취해가시면 될 것 같습니다 :) 10 | 11 | ## 뷰 CLI로 생성한 기본 폴더 구조 12 | 13 | 뷰 CLI 2.9 버전을 이용하여 webpack-simple 프로젝트를 아래와 같이 생성합니다. 14 | 15 | ```bash 16 | vue init webpack-simple folder-structure 17 | ``` 18 | 19 | 프로젝트를 생성하고 나면 기본적인 폴더 구조는 아래와 같이 구성됩니다. 20 | 21 | ```bash 22 | . 23 | ├─ README.md 24 | ├─ index.html 25 | ├─ webpack.config.js 26 | ├─ package.json 27 | └─ src 28 | ├─ main.js 29 | ├─ App.vue 30 | └─ assets 31 | └─ logo.png 32 | ``` 33 | 34 | ## 기능 별로 구분한 폴더 구조 35 | 36 | 실무에서 개발할 때 필수로 사용되는 라우터, 상태 관리, 필터, 다국어, 플러그인 등을 이용하면 아래와 같이 폴더를 구분할 수 있습니다. 37 | 38 | ```bash 39 | . 40 | ├─ README.md 41 | ├─ index.html 42 | ├─ webpack.config.js 43 | ├─ package.json 44 | └─ src 45 | ├─ main.js 46 | ├─ App.vue 47 | ├─ components 컴포넌트 48 | │ ├─ common 49 | │ └─ ... 50 | ├─ router 라우터 51 | │ ├─ index.js 52 | │ └─ routes.js 53 | ├─ views 라우터 페이지 54 | │ ├─ MainView.vue 55 | │ └─ ... 56 | ├─ store 상태 관리 57 | │ ├─ auth 58 | │ ├─ index.js 59 | │ └─ ... 60 | ├─ api api 함수 61 | │ ├─ index.js 62 | │ ├─ users.js 63 | │ └─ ... 64 | ├─ utils 필터 등의 유틸리티 함수 65 | │ ├─ filters.js 66 | │ ├─ bus.js 67 | │ └─ ... 68 | ├─ mixins 믹스인 69 | │ ├─ index.js 70 | │ └─ ... 71 | ├─ plugins 플러그인 72 | │ ├─ ChartPlugin.js 73 | │ └─ ... 74 | ├─ translations 다국어 75 | │ ├─ index.js 76 | │ ├─ en.json 77 | │ └─ ... 78 | └─ assets css 등의 웹 자원 79 | ├─ css 80 | ├─ images 81 | └─ ... 82 | ``` -------------------------------------------------------------------------------- /docs/advanced/transition.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Transition & Animation 3 | --- 4 | 5 | # Transition & Animation 6 | 7 | 뷰는 라이브러리 내부적으로 트랜지션, 애니메이션 기능을 갖고 있습니다. 그래서 간단한 규칙과 속성들만 알면 쉽게 멋진 애니메이션 효과를 추가할 수 있습니다. 8 | 9 | ## 트랜지션 예시 10 | 11 | 뷰 트랜지션 코드를 간단히 살펴보겠습니다. 12 | 13 | ```html 14 |
15 | 16 | 17 |

This is a comment

18 |
19 |
20 | ``` 21 | 22 | ```js 23 | new Vue({ 24 | ... 25 | data: { 26 | status: false 27 | }, 28 | methods: { 29 | showComment() { 30 | this.status = true; 31 | } 32 | } 33 | }) 34 | ``` 35 | 36 | ```css 37 | .fade-enter-active, .fade-leave-active { 38 | transition: opacity .5s; 39 | } 40 | .fade-enter, .fade-leave-to { 41 | opacity: 0; 42 | } 43 | ``` 44 | 45 | 위 코드에서 show 버튼을 클릭하면 This is a comment 라는 텍스트가 부드럽게 살며시 표시됩니다. 여기서 주목할 코드는 ``이라는 태그입니다. 46 | 47 | `` 태그는 `name` 속성을 갖고 있고, 해당 `name` 속성과 연관된 CSS 코드가 위에 정의되어 있습니다. CSS 코드에 따라서 텍스트가 표시될 때 opacity의 값이 변화되고, 이에 따라 살며시 나타나는 효과를 볼 수가 있습니다. 48 | 49 | ## 트랜지션 클래스 50 | 51 | 앞의 코드에서 트랜지션 효과가 나타날 수 있었던 것은 바로 트랜지션 태그의 `name` 속성 덕택입니다. `name` 속성에 맞춰 아래와 같이 CSS 코드를 구현했었습니다. 52 | 53 | ```html {1} 54 | 55 | 56 | ``` 57 | 58 | ```css {1,4} 59 | .fade-enter-active, .fade-leave-active { 60 | transition: opacity .5s; 61 | } 62 | .fade-enter, .fade-leave-to { 63 | opacity: 0; 64 | } 65 | ``` 66 | 67 | `fade-enter-active`, `fade-leave-active` 등에서 볼 수 있듯이 뷰의 트랜지션 CSS 코드는 일정한 규칙을 68 | 갖습니다. 여기서 사용하는 CSS 클래스는 아래와 같이 6개가 있습니다. 69 | 70 | ![콘솔에서 확인한 인스턴스 내용](../.vuepress/public/images/transition-flow.png) 71 | 72 | 일반적으로 `v-enter`, `v-leave-to`를 함께 사용하고, `v-enter-to`, `v-leave`를 함께 사용합니다. 그림의 색깔을 보면 짝 지어져서 잘 구분되어 있습니다. -------------------------------------------------------------------------------- /docs/composition/computed.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Computed API 🆕 3 | --- 4 | 5 | # computed API 6 | 7 | 컴퓨티드(computed) API는 컴포지션(Composition API)에서 사용된 [컴퓨티드 속성](/syntax/computed.html)을 의미합니다. 이 페이지에서는 컴포지션에서 8 | 컴퓨티드 속성을 어떻게 사용할 수 있는지 살펴보겠습니다. 9 | 10 | :::tip 11 | 컴퓨티드(computed) 속성은 뷰에서 자주 사용되는 속성입니다. 템플릿 표현식의 코드를 간결하게 해주고 API에서 받은 데이터를 가공할 때 연산 로직을 단순화 해줍니다. 12 | ::: 13 | 14 | ## computed API 소개 15 | 16 | 인스턴스 옵션 속성 방식으로 작성한 컴퓨티드 속성 코드입니다. 17 | 18 | ```html 19 | 22 | 23 | 37 | ``` 38 | 39 | 위 코드는 컴퓨티드 속성을 사용해 `Hello` 문자열의 순서를 뒤집어 `olleH`로 화면에 표시했습니다. 이 코드를 컴포지션 스타일로 작성하면 다음과 같습니다. 40 | 41 | ```html 42 | 45 | 46 | 63 | ``` 64 | 65 | 컴포지션에서 컴퓨티드 속성을 쓰기 위해서는 먼저 위와 같이 `computed` API를 라이브러리에서 임포트해야 합니다. 그리고 위 `reversedMessage` 함수가 선언된 것처럼 `computed` API를 호출하고 안에 콜백으로 컴퓨티드 속성으로 정의될 값을 작성합니다. 작성된 코드를 보면 인스턴스 옵션 속성으로 작성한 코드와 크게 다르지 않습니다. 다만, `message.split()....` 형태가 아니라 `message.value.split()...`와 같이 `message.value` 값을 사용해야 합니다. 66 | 67 | :::tip 68 | 왜 `ref`로 선언된 값은 `setup` 함수 안에서 `.value`로 접근해야 할까요? 자세한 내용은 다음 링크를 참고하세요 :) [컴포지션의 .value](/reuse/composition.html#ref-두-번째-특징-value) 69 | ::: 70 | 71 | ## 용어 정리 72 | 73 | - 컴퓨티드 속성 : Vue 2에서 사용하던 컴퓨티드 속성 74 | - 컴퓨티드 API : 컴포지션 스타일로 작성된 setup 안에서의 컴퓨티드 속성 -------------------------------------------------------------------------------- /docs/composition/event-emit.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Event Emit - setup() 🆕 3 | --- 4 | 5 | # 이벤트 발생 - setup() 6 | 7 | 이벤트 발생(event emit)은 하위 컴포넌트에서 상위 컴포넌트로 신호를 보내는 컴포넌트 통신 방식입니다. 컴포지션에서는 어떻게 컴포넌트 이벤트를 발생시킬 수 있는지 알아보겠습니다. 8 | 9 | ## 컴포넌트 이벤트 발생 10 | 11 | 기존에 인스턴스 옵션 속성으로 이벤트를 발생시키는 방법은 [$emit() API](/vue/event-emit)였습니다. 12 | 13 | ```html 14 | 23 | ``` 24 | 25 | 위 코드는 하위 컴포넌트에서 상위 컴포넌트로 `change` 이벤트를 보내는 코드입니다. 이처럼 `$emit()` API를 이용하여 이벤트를 발생시킬 수 있습니다. 26 | 27 | ## setup()에서 컴포넌트 이벤트 발생시키기 28 | 29 | 이번엔 `setup()` 함수에서 이벤트를 발생시키는 방법을 알아보겠습니다. 30 | 31 | ```html 32 | 39 | ``` 40 | 41 | 위 코드는 `setup()` 함수의 두 번째 파라미터 `context`를 이용하여 이벤트를 발생시킨 코드입니다. `setup()` 함수의 첫 번째 파라미터는 프롭스 속성을 의미하고 두 번째 파라미터는 이벤트를 발생시킬 수 있는 `emit`을 비롯하여 attrs, slots, expose 등을 가진 [컨텍스트 객체(Context Object)](https://vuejs.org/api/composition-api-setup.html#setup-context)를 의미합니다. 42 | 43 | 이 `context.emit()`은 기존 `$emit()`와 사용법이 동일합니다. 단순히 이벤트를 보낼 수도 있고 아래와 같이 이벤트의 인자를 넘길 수도 있습니다. 44 | 45 | ```js 46 | context.emit('change'); // change 이벤트만 발생 47 | context.emit('change', 100); // change 이벤트를 발생시키고 인자 100을 같이 넘김 48 | ``` 49 | 50 | ## 이벤트 발생의 디스트럭처링 문법 51 | 52 | `context.emit()`은 다음과 같이 디스트럭처링 문법을 사용해도 됩니다. 53 | 54 | ```html 55 | 62 | ``` 63 | 64 | 첫 번째 파라미터 `props`는 디스트럭처링을 썼을 때 [반응성이 사라지기 때문에 주의해야 했지만](/composition/props.html#디스트럭처링을-쓰고-싶다면), `emit`은 반응성이 주입된 값이 아니라 단순히 호출만 하는 API이기 때문에 반응성이 제거되는 부분을 걱정하지 않아도 됩니다. -------------------------------------------------------------------------------- /docs/composition/img/afterToRefs.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/joshua1988/vue-camp/1d2b5ed08f37e891e5dd2c762a9cc25d2351a9dc/docs/composition/img/afterToRefs.png -------------------------------------------------------------------------------- /docs/composition/script-setup.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Script Setup 🆕 3 | --- 4 | 5 | # ` 36 | ``` 37 | 38 | 위와 같이 컴포넌트 안에서 컴포지션으로만 컴포넌트의 로직을 작성하는 경우 아래와 같이 스크립트 태그에 `setup`을 추가해서 코드를 간결하게 작성할 수 있습니다. 39 | 40 | ```html{6} 41 | 45 | 46 | 57 | ``` 58 | 59 | 이 코드는 앞에서 살펴본 코드와 같은 코드입니다. 반응성이 주입된 `message` 데이터와 `changeMessage()` 함수는 별도로 익스포트하거나 추가적인 작업을 하지 않아도 템플릿 표현식에서 사용할 수 있게 됩니다. `setup()` 속성을 정의하면 매번 그 안에서 정의된 데이터와 메서드 등은 반환해줘야 하기 때문에 이 번거로운 절차를 줄여준 것이죠. 60 | 61 | ## 주의할 점 62 | 63 | ` 78 | ``` 79 | 80 | 위 코드에서 `message` 변수는 반응성이 주입되지 않은 일반 변수입니다. `let`으로 선언되었기 때문에 변수의 값을 바꿀 수 있죠. 변경 버튼을 눌러 `changeMessage` 메서드가 실행되면 `message` 값을 `Hello`로 바꿀 겁니다. 81 | 82 | 실제로 버튼을 눌러보면 스크립크 레벨에서는 `message`의 값이 바뀌지만 화면에는 바뀐 값이 표시되지 않는 것을 확인할 수 있습니다. 이렇게 동작하는 이유는 `message` 값에 반응성이 주입되지 않고 일반 변수로 취급된 상태에서 템플릿 표현식에 표시되었기 때문입니다. 그래서 함수가 정상적으로 실행되었지만 화면의 값은 바뀌지 않죠. 83 | 84 | 만약 값이 바뀌었을 때 반응성에 의해 정상적으로 변경된 데이터가 화면에 표시하게 하려면 다음과 같이 코드를 수정하면 됩니다. 85 | 86 | ```html 87 | 96 | ``` 97 | 98 | 이처럼 ` 35 | ``` 36 | 37 | 위 코드는 `message` 값을 변경할 때마다 브라우저 콘솔에 변경된 값이 출력되는 코드입니다. 38 | 39 | 이번엔 위 코드를 컴포지션 스타일의 watch API로 변경해 보겠습니다. 40 | 41 | ```html 42 | 57 | ``` 58 | 59 | 앞에서 살펴본 코드와 동일하게 변화를 감지할 데이터를 watch API의 첫 번째 인자로 선언하고, 두 번째 인자에 실행될 로직을 적었습니다. 60 | 61 | ## 용어 정리 62 | 63 | - watch 속성 : Vue 2에서 사용하던 watch 속성 64 | - watch API : 컴포지션 스타일로 작성된 setup 안에서의 watch 속성 -------------------------------------------------------------------------------- /docs/d3/README.md: -------------------------------------------------------------------------------- 1 | --- 2 | orders: [d3.md, vue-with-d3, tutorial] 3 | --- 4 | 5 | [[toc]] 6 | 7 | toc 8 | 9 | [toc 10 | ] -------------------------------------------------------------------------------- /docs/d3/images/d3-line-axis.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/joshua1988/vue-camp/1d2b5ed08f37e891e5dd2c762a9cc25d2351a9dc/docs/d3/images/d3-line-axis.png -------------------------------------------------------------------------------- /docs/d3/images/d3-line-path.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/joshua1988/vue-camp/1d2b5ed08f37e891e5dd2c762a9cc25d2351a9dc/docs/d3/images/d3-line-path.png -------------------------------------------------------------------------------- /docs/d3/images/tutorial-npm-vue.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/joshua1988/vue-camp/1d2b5ed08f37e891e5dd2c762a9cc25d2351a9dc/docs/d3/images/tutorial-npm-vue.png -------------------------------------------------------------------------------- /docs/deploy/cli3-rules.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: CLI v3.x Rules 3 | --- 4 | 5 | # 최신 뷰 CLI의 빌드 환경 규칙 6 | 7 | 이번 챕터에서는 뷰 CLI 버전 3 이상에서만 적용되는 몇 가지 빌드 환경 규칙을 알아보겠습니다. 8 | 9 | ## 애플리케이션 모드 10 | 11 | 뷰 CLI 3에서는 다음과 같이 크게 3가지 모드가 있습니다. 12 | 13 | - `development` : 프로토타이핑 및 개발 용도. `npm run serve` 명령어로 실행할 때의 모드 14 | - `production` : 상용화 및 배포 용도. `npm run build` 명령어로 실행할 때의 모드 15 | - `test` : 테스트 용도. `npm run test:unit` 명령어로 실행할 때의 모드 16 | 17 | 위의 모드는 `NODE_ENV` 변수 값과도 연관이 있습니다. 개발 모드로 실행한 경우에는 자동으로 `NODE_ENV` 값이 `development`로 설정이 되고, 배포 모드로 실행한 경우에는 `production`으로 설정됩니다. 18 | 19 | ## 애플리케이션 모드에 따라 뷰 CLI가 해주는 일? 20 | 21 | 뷰 CLI로 생성하여 애플리케이션을 제작하게 되면 기본적으로 웹팩을 사용합니다. 따라서, 모드에 따라 웹팩의 설정이 달라집니다. 예를 들면, 개발 모드일 때는 웹팩 데브 서버를 실행하기 때문에 빠르게 빌드 하면서 프로토타이핑 해나갈 수 있고 상용 모드일 때는 웹팩으로 빌드된 파일의 이름에 해쉬 값을 붙여 캐싱과 같은 이점을 누릴 수 있습니다. 22 | 23 | ## 환경 변수 파일 규칙 24 | 25 | 뷰 CLI 3에서는 프로젝트 루트 폴더에 아래와 같은 규칙으로 환경 변수 파일을 생성할 수 있습니다. 26 | 27 | ```bash 28 | .env # 모든 모드에 적용되는 환경 변수 파일 29 | .env.local # 모든 모드에 적용되나 개인만 사용하는 파일(git에 올라가지 않음) 30 | .env.[mode] # 특정 모드에 해당하는 환경 변수 파일 31 | .env.[mode].local # 특정 모드에 해당하지만 개인이 사용하는 파일(git에 올라가지 않음) 32 | ``` 33 | 34 | 여기서 말하는 모드는 앞에서 살펴봤던 애플리케이션 모드를 의미합니다. 예를 들어, 상용 버전에 해당하는 환경 변수 파일은 아래와 같습니다. 35 | 36 | ```bash 37 | .env.production 38 | ``` 39 | 40 | ## 환경 변수 파일 적용 순서 41 | 42 | 아래와 같이 개발 환경인지 배포 환경인지에 따라 여러 개의 환경 변수 파일을 분리할 수도 있습니다. 43 | 44 | - .env 45 | - .env.development 46 | - .env.production 47 | 48 | ```bash 49 | # .env 50 | VUE_APP_URL=https://domain.com 51 | ``` 52 | 53 | ```bash 54 | # .env.development 55 | VUE_APP_URL=https://localhost:8080 56 | ``` 57 | 58 | ```bash 59 | # .env.production 60 | VUE_APP_URL=https://123.123.123.123:9090 61 | ``` 62 | 63 | 이때 배포 모드인 `npm run build` 명령어를 입력하게 되면 `.env.production` 파일의 내용이 가장 높은 우선순위를 갖게 됩니다. 따라서, 애플리케이션에서 사용한 `VUE_APP_URL` 값은 아래와 같이 설정됩니다. 64 | 65 | ```js 66 | // main.js 67 | console.log(VUE_APP_URL) // https://123.123.123.123:9090 68 | ``` 69 | 70 | 위처럼 특정 모드에 해당하는 환경 변수의 파일의 값이 가장 높은 우선순위를 갖게 됩니다. 71 | 72 | :::tip 73 | 만약 `.env.development`, `.env.production` 등의 파일이 없다면 `.env` 파일에 설정한 값이 최종 값이 됩니다. 74 | ::: 75 | 76 | ## 개발할 때는 로컬 환경 변수를 사용 77 | 78 | 앞의 규칙들을 인지한 상태에서 팀 공용으로 사용하는 환경 변수 이외에 개인적으로 환경 변수를 설정하여 사용할 수 있습니다. 79 | 80 | ```bash 81 | .env.development # 팀 공용 환경 변수 82 | .env.development.local # 개인 디버깅 또는 개발용 환경 변수 83 | ``` 84 | 85 | 팀 공용으로 사용하는 애플리케이션 설정 값들은 `.env.development` 파일에 관리하고, 개인적으로 로컬 또는 특정 서버 디버깅을 위해 `.env.development.local` 파일에 관리하면 좋습니다. 86 | 87 | ```bash 88 | # .env.development 89 | VUE_APP_URL=http://internal.server.address:8080 90 | ``` 91 | 92 | ```bash 93 | # .env.development.local 94 | VUE_APP_URL=http://localhost:8081 95 | ``` 96 | 97 | 위와 같이 활용하는 경우 `.local` 파일은 git에도 올라가지 않기 때문에 편하게 API 엔드포인트(URL)를 바꿔서 사용할 수 있습니다. 98 | -------------------------------------------------------------------------------- /docs/deploy/env-setup.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Environment Variables 3 | --- 4 | 5 | # 환경 변수 파일을 이용한 옵션 설정 6 | 7 | 환경 변수 파일이란 애플리케이션이 실행될 때 특정 값을 넘길 수 있는 변수를 의미합니다. 웹 애플리케이션 관점에서는 `.env` 파일에 정의된 변수를 의미하며 미리 정의된 값을 애플리케이션에서 활용하고 싶을 때 사용합니다. 8 | 9 | 이번 챕터에서는 Vue.js 애플리케이션에서 `.env` 파일을 활용하는 방법에 대해서 알아보겠습니다. 10 | 11 | ## env 파일 12 | 13 | CLI로 생성한 프로젝트로 개발 및 배포를 진행할 때 `.env`라는 환경 변수 파일로 옵션들을 편하게 바꿀 수 있습니다. 14 | 15 | ```bash 16 | # .env 파일 17 | VUE_APP_LOCAL_URI=http://localhost:8080/ 18 | VUE_APP_TEST_SERVER=http://test.com:9090/ 19 | 20 | clientId=client-test1234 21 | clientServer=server-test1234 22 | ``` 23 | 24 | 위에서 설정한 변수들을 가지고 애플리케이션 로직에 활용할수도 있고, 웹팩으로 빌드를 할 때 위 변수의 내용을 반영할수도 있습니다. 25 | 26 | 예를 들어 아래와 같이 API의 호출 URL 값으로 `.env` 파일에 정의한 `VUE_APP_LOCAL_URI`를 사용할 수 있습니다. 27 | 28 | ```js 29 | // api/index.js 30 | function fetchUser() { 31 | return axios.get(`${VUE_APP_LOCAL_URI}users`); 32 | } 33 | ``` 34 | 35 | 위와 같이 서비스 코드에서 `.env` 파일에 지정한 변수를 활용하려면 아래와 같이 웹팩에 추가 설정을 해줘야 합니다. 36 | 37 | ```js 38 | // webpack.config.js 39 | const webpack = require('webpack'); 40 | const dotenv = require('dotenv'); 41 | const env = dotenv.config().parsed; 42 | 43 | plugins: [ 44 | new webpack.DefinePlugin({ 45 | VUE_APP_LOCAL_URI: JSON.stringify(env.VUE_APP_LOCAL_URI), 46 | }), 47 | ], 48 | ``` 49 | 50 | ## Vue CLI 3.x 버전의 환경 변수 파일 접근 51 | 52 | 최신 뷰 CLI에서는 위와 같이 웹팩의 DefinePlugin을 설정하지 않아도 환경 변수를 쉽게 접근할 수 있습니다. 환경 변수 파일의 변수 명을 아래와 같은 방식으로 정의하면 됩니다. 53 | 54 | ```bash 55 | VUE_APP_NUM=10 56 | VUE_APP_STR=hi 57 | ``` 58 | 59 | 변수 명 앞에 항상 `VUE_APP_` 를 붙여주면 Vue CLI에서 내부적으로 웹팩 DefinePlugin을 활용하여 클라이언트 웹 자원에서 접근할 수 있게 설정됩니다. 60 | 61 | ```js 62 | // main.js 63 | import Vue from 'vue'; 64 | // ... 65 | 66 | console.log(VUE_APP_NUM); // 10 67 | 68 | new Vue({ 69 | // ... 70 | }) 71 | ``` 72 | 73 | ```html 74 | 75 | 78 | 79 | 86 | ``` 87 | 88 | 이와 같은 방식으로 아래의 환경 변수들도 사용할 수 있습니다. 89 | 90 | - `NODE_ENV` : 애플리케이션 모드를 가리키는 변수 `development`, `production`, `test` 91 | - `BASE_URL` : `vue.config.js` 파일에 정의된 `publicPath`의 값과 동일한 변수 92 | 93 | -------------------------------------------------------------------------------- /docs/deploy/intro.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: General Guide 3 | --- 4 | 5 | # CLI로 생성한 프로젝트 배포하기 6 | 7 | Vue CLI로 생성한 프로젝트를 다 구현한 뒤 서버에 배포하는 방법에 대해서 다룹니다. 8 | 9 | ## 배포 명령어 10 | 11 | `npm run build` 12 | 13 | CLI로 생성한 프로젝트를 서비스에 배포하려면 제일 먼저 위 명령어를 실행해야 합니다. 실행하고 나면 아래와 같이 호스팅 할 수 있는 형태의 HTML, CSS, Javascript, 이미지 등의 파일이 생성되죠. 이렇게 생성된 자원을 빌드된 자원이라고 부릅니다. 14 | 15 | ![뷰 컴포넌트 통신 방식](../.vuepress/public/images/deploy-folder-structure.png) 16 | 17 | ## 웹 서버에 빌드된 자원 배포하기 18 | 19 | 앞에서 생성한 빌드 자원을 각각의 서버에 배포하기 위해서는 각 서버에 추가적인 세팅이 필요합니다. 특히 뷰 라우터를 활용하여 싱글 페이지 애플리케이션을 제작하신 경우에는 서버에 꼭 페이지 fallback 옵션을 추가해주셔야 해당 url로 접근했을 때 정상적으로 동작합니다. 각 웹 서버의 fallback 설정 방법은 아래 공식 문서를 참고하세요. 20 | 21 | [Server Configuration Guide - Vue Router](https://router.vuejs.org/guide/essentials/history-mode.html#example-server-configurations) -------------------------------------------------------------------------------- /docs/design/pattern1.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Common Approach 3 | --- 4 | 5 | # 일반적인 컴포넌트 구조화 방식 6 | 7 | 첫 번째 컴포넌트 디자인 패턴은 일반적인 컴포넌트 구조화 방식입니다. 뷰 컴포넌트, 컴포넌트 통신 방식을 배우고 나면 자연스럽게 아래와 같이 컴포넌트를 구현하게 됩니다. 8 | 9 | ```html 10 | 15 | 16 | 29 | ``` 30 | 31 | 위와 같은 방식은 등록된 컴포넌트가 여러 곳에 쓰이지 않을 때 사용하기 좋은 방식입니다. 실질적인 코드의 재사용성보다는 템플릿 코드의 가독성과 명시적인 코드의 모양새를 더 중점으로 두고 있습니다. 32 | 33 | 위의 코드가 잘 이해되지 않는다면 아래 챕터를 다시 살펴보시기 바랍니다. 34 | 35 | - [컴포넌트](/vue/components.html) 36 | - [컴포넌트 통신 방식](/vue/components-communication.html) 37 | - [프롭스 속성](/vue/props.html) 38 | - [이벤트 발생](/vue/event-emit.html) -------------------------------------------------------------------------------- /docs/design/pattern2.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Building Controlled Components 3 | --- 4 | 5 | # 결합력 높은 컴포넌트 6 | 7 | 두 번째 컴포넌트 디자인 패턴의 핵심은 v-model 디렉티브입니다. v-model의 내부가 어떻게 동작하는지 이해하고 이를 응용하여 좀 더 결합력이 높은 컴포넌트를 만들어보겠습니다. 8 | 9 | ## v-model 디렉티브 10 | 11 | v-model 디렉티브는 양방향 데이터 바인딩을 지원하는 속성입니다. 양방향 데이터 바인딩이란 화면의 데이터와 뷰 인스턴스의 데이터가 항상 일치하는 것을 의미합니다. 코드를 보겠습니다. 12 | 13 | ```html 14 | 17 | 18 | 27 | ``` 28 | 29 | 위 코드를 실행하면 인풋 박스의 초기 값으로 'hi'가 지정되어 있습니다. 그리고 인풋 박스의 내용을 바꾸면 inputText의 값도 같이 바뀝니다. 해당 내용은 뷰 개발자 도구에서 확인할 수 있습니다. 30 | 31 | ## v-model 디렉티브의 동작 방식 32 | 33 | 그럼 위에서 v-model 디렉티브가 어떻게 뷰 인스턴스의 데이터와 정보를 주고 받았을까요? v-model 디렉티브의 내부는 아래와 같은 구조로 동작합니다. 34 | 35 | ```html 36 | 39 | 40 | 49 | ``` 50 | 51 | `inputText`의 값을 `:value`에 연결하고 인풋 박스의 입력을 모두 `$event.target.value`로 `inputText`에 넣습니다. 위의 코드는 v-model 디렉티브와 동일하게 동작합니다. 52 | 53 | ::: tip 54 | 위와 같은 코드는 커스텀 디렉티브를 작성할 때 많이 사용됩니다. 55 | ::: 56 | 57 | ## v-model로 체크 박스 컴포넌트 만들기 58 | 59 | 앞에서 살펴본 v-model로 HTML 인풋 체크 박스를 컴포넌트화 해보겠습니다. 먼저 상위 컴포넌트인 App.vue의 코드입니다. 60 | 61 | ```html 62 | 63 | 66 | 67 | 81 | ``` 82 | 83 | 이어서 하위 컴포넌트로 등록된 CheckBox.vue의 코드를 보겠습니다. 84 | 85 | ```html 86 | 87 | 90 | 91 | 101 | ``` 102 | 103 | 위 코드를 실행하여 체크 박스를 클릭하면 `checked` 값이 정상적으로 true에서 false로 전환되는 것을 확인할 수 있습니다. -------------------------------------------------------------------------------- /docs/design/pattern3.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Component with Slots 3 | --- 4 | 5 | # 슬롯을 이용한 컴포넌트 템플릿 확장 6 | 7 | 세 번째로 살펴볼 컴포넌트 디자인 패턴은 슬롯을 이용한 컴포넌트 설계 방법입니다. [슬롯](/reuse/slots.html) 챕터에서 이미 살펴봤듯이 슬롯은 하위 컴포넌트의 템플릿을 상위 컴포넌트에서 유연하게 확장할 수 있는 기능입니다. 8 | 9 | 슬롯은 탭, 모달(팝업), 버튼 등 흔히 사용되는 UI 컴포넌트를 모두 재사용 할 수 있게 도와줍니다. 예시 코드를 살펴보겠습니다. 10 | 11 | ```html {4} 12 | 13 | 18 | ``` 19 | 20 | ```html {5,7-10} 21 | 22 | 33 | 34 | 43 | ``` 44 | 45 | 위 코드는 버튼의 최소 마크업을 갖는 BaseButton 컴포넌트를 생성한 후 슬롯을 이용하여 버튼의 내용이 확장될 수 있게 구조화한 코드입니다. BaseButton.vue에서 `` 태그를 넣어놨기 때문에 BaseButton 컴포넌트를 등록하여 사용할 때 상위 컴포넌트에서 텍스트를 넣어 버튼의 이름만 바꾸거나, 텍스트와 아이콘을 함께 넣어 버튼의 UI를 꾸밀 수도 있습니다. -------------------------------------------------------------------------------- /docs/design/pattern4.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Renderless Components 3 | --- 4 | 5 | # Pattern 4 6 | 7 | 업데이트 예정 -------------------------------------------------------------------------------- /docs/design/pattern5.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: High Order Components 3 | --- 4 | 5 | # 컴포넌트의 코드마저 재사용하는 하이 오더 컴포넌트 6 | 7 | ## 정의 8 | 9 | 뷰의 하이 오더 컴포넌트는 리액트의 하이 오더 컴포넌트에서 기원된 것입니다. 리액트의 [하이 오더 컴포넌트 소개 페이지](https://reactjs.org/docs/higher-order-components.html)를 보면 아래와 같이 정확한 정의가 나와 있습니다. *A higher-order component (HOC) is an advanced technique in React for reusing component logic*. 이 말을 정리해보면 다음과 같습니다. 10 | 11 | 하이 오더 컴포넌트는 **컴포넌트의 로직(코드)을 재사용하기 위한 고급 기술**입니다 12 | 13 | ## 반복되는 컴포넌트 로직 14 | 15 | 여기서 컴포넌트의 로직을 재사용한다는 말이 무슨 의미일까요? 이 표현에서 가리키고 있는 컴포넌트 로직이란 뷰에서 **인스턴스 옵션을 의미**합니다. 코드로 바로 살펴보겠습니다. 16 | 17 | ```html 18 | 19 | 28 | 29 | 40 | ``` 41 | 42 | ```html 43 | 44 | 51 | 52 | 63 | ``` 64 | 65 | 위 코드는 ProductList 라는 컴포넌트와 UserList 컴포넌트의 로직을 정의한 코드입니다. 두 컴포넌트가 각각 상품과 사용자 정보를 서버에서 받아와 표시해주는 컴포넌트라고 가정했을 때, 공통적으로 들어가는 코드는 다음과 같습니다. 66 | 67 | ```js 68 | name: '컴포넌트 이름', 69 | mounted() { 70 | bus.$emit('off:loading'); 71 | }, 72 | ``` 73 | 74 | `name`은 컴포넌트의 이름을 정의해주는 속성이고, `mounted()`에서 사용한 이벤트 버스는 서버에서 데이터를 다 받아왔을 때 스피너나 프로그레스 바와 같은 로딩 상태를 완료해주는 코드입니다. 이 두 컴포넌트 이외에도 서버에서 데이터 목록을 받아와 표시해주는 컴포넌트가 있다면 또 비슷한 로직이 반복될 것입니다. 75 | 76 | **이 때 이 반복되는 코드를 줄여줄 수 있는 패턴이 바로 하이 오더 컴포넌트입니다.** 77 | 78 | ## 하이 오더 컴포넌트로 반복 코드 줄이기 79 | 80 | 이 반복되는 코드를 줄이기 위해 하이 오더 컴포넌트를 구현해보겠습니다. 81 | 82 | ```js 83 | // CreateListComponent.js 84 | import bus from './bus.js' 85 | import ListComponent from './ListComponent.vue'; 86 | 87 | export default function createListComponent(componentName) { 88 | return { 89 | name: componentName, 90 | mounted() { 91 | bus.$emit('off:loading'); 92 | }, 93 | render(h) { 94 | return h(ListComponent); 95 | } 96 | } 97 | } 98 | ``` 99 | 100 | 위 코드는 CreateListComponent라는 하이 오더 컴포넌트를 구현한 코드입니다. 하이 오더 컴포넌트를 적용할 컴포넌트들의 공통 코드들(mounted, name 등)을 미리 정의했습니다. 그럼 이제 이 하이 오더 컴포넌트를 어떻게 사용할까요? 아래를 보겠습니다. 101 | 102 | ```js 103 | // router.js 104 | import createListComponent from './createListComponent.js'; 105 | 106 | new VueRouter({ 107 | routes: [ 108 | { 109 | path: 'products', 110 | component: createListComponent('ProductList') 111 | }, 112 | { 113 | path: 'users', 114 | component: createListComponent('UserList') 115 | }, 116 | ... 117 | ] 118 | }) 119 | ``` 120 | 121 | 위와 같은 방식으로 하이 오더 컴포넌트를 임포트 하고, 각 컴포넌트의 이름만 정의를 해주면 컴포넌트의 기본 공용 로직인 `mounted()`, `name`를 가지고 컴포넌트가 생성됩니다. 따라서, 컴포넌트마다 불 필요하게 반복되는 코드를 정의하지 않아도 됩니다. -------------------------------------------------------------------------------- /docs/es6+/async-await.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Async & Await 3 | --- 4 | 5 | # Async & Await 6 | 7 | 어싱크 어웨이트는 자바스크립트 비동기 처리 패턴의 최신 문법입니다. Promise와 Callback에서 주는 단점들을 해결하고 자바스크립트의 비동기적 사고 방식에서 벗어나 동기적(절차적)으로 코드를 작성할 수 있게 도와줍니다. 8 | 9 | ## 기본 문법 10 | 11 | async 함수의 기본 문법은 다음과 같습니다. 12 | 13 | ```js 14 | async function fetchData() { 15 | await getUserList(); 16 | } 17 | ``` 18 | 19 | async 함수는 함수의 앞에 `async`를 붙여주고 함수의 내부 로직 중 비동기 처리 로직 앞에 `await`를 붙여주면 됩니다. 좀 더 정확하게 말하면 Promise 객체를 반환하는 API 호출 함수 앞에 `await`를 붙입니다. 20 | 21 | ## 기본 예제 22 | 23 | 다음 코드를 보겠습니다. 24 | 25 | ```js 26 | async function fetchData() { 27 | var list = await getUserList(); 28 | console.log(list); 29 | } 30 | 31 | function getUserList() { 32 | return new Promise(function(resolve, reject) { 33 | var userList = ['user1', 'user2', 'user3']; 34 | resolve(userList); 35 | }); 36 | } 37 | ``` 38 | 39 | `fetchData()` 함수에서 `getUserList()` 함수를 호출하고 나면 Promise 객체가 반환됩니다. 그리고 그 Promise는 실행이 완료된 상태(resolve)이며 실행의 결과로 `userList` 배열을 반환하고 있습니다. 따라서 `fetchData()`를 호출하면 `userList`의 배열이 출력됩니다. 40 | 41 | ```js 42 | fetchData(); // ['user1', 'user2', 'user3'] 43 | ``` 44 | 45 | 46 | 47 | ## (부록) Async & Await 문법을 사용하기 위한 바벨 플러그인 설정 48 | 49 | 뷰 최신 CLI 도구는 별도의 바벨 플러그인을 설치하지 않아도 바로 async & await 문법을 사용할 수 있습니다. 하지만, 뷰 CLI 2.x 버전대는 아래와 같은 추가 설정이 필요합니다. 50 | 51 | 1. 다음 바벨 플러그인을 설치한다. 52 | 53 | ``` 54 | npm i babel-plugin-transform-runtime 55 | ``` 56 | 57 | 2. .babelrc 파일에 아래와 같은 설정을 추가한다. 58 | 59 | ``` 60 | "plugins": ["transform-runtime"] 61 | ``` -------------------------------------------------------------------------------- /docs/es6+/class.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/joshua1988/vue-camp/1d2b5ed08f37e891e5dd2c762a9cc25d2351a9dc/docs/es6+/class.md -------------------------------------------------------------------------------- /docs/es6+/const-let.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Const & Let 3 | --- 4 | 5 | # const & let 6 | 7 | const와 let 예약어는 ES6에서 사용하는 변수 선언 방식입니다. 8 | 9 | ## let 10 | 11 | let 예약어는 한번 선언하면 다시 선언할 수 없습니다. 12 | 13 | ```js 14 | // 똑같은 변수를 재선언할 때 오류 15 | let a = 10; 16 | let a = 20; // Uncaught SyntaxError: Identifier 'a' has already been declared 17 | ``` 18 | 19 | ## const 20 | 21 | const 예약어는 한번 할당한 값을 변경할 수 없습니다. 22 | 23 | ```js 24 | // 값을 다시 할당했을 때 오류 25 | const a = 10; 26 | a = 20; // Uncaught TypeError: Assignment to constant variable. 27 | ``` 28 | 29 | 단, 객체 `{}`또는 배열 `[]`로 선언했을 때는 객체의 속성(property)과 배열의 요소(element)를 변경할 수 있습니다. 30 | 31 | ```js 32 | // 객체로 선언하고 속성 값을 변경 33 | const b = { 34 | num: 10, 35 | text: 'hi' 36 | }; 37 | console.log(b.num); // 10 38 | 39 | b.num = 20; 40 | console.log(b.num); // 20 41 | ``` 42 | 43 | ```js 44 | // 배열로 선언하고 배열 요소를 추가 45 | const c = []; 46 | console.log(c); // [] 47 | 48 | c.push(10); 49 | console.log(c); // [10] 50 | ``` 51 | 52 | ## 블록 유효범위 53 | 54 | ES5의 var를 이용한 변수 선언 방식과 let & const를 이용한 변수 선언 방식의 가장 큰 차이점은 블록 유효범위입니다. 55 | 56 | ## var의 유효 범위 57 | 58 | var의 유효 범위는 함수의 블록 단위로 제한됩니다. 흔히 함수 스코프(function scope)라고 표현합니다. 59 | 60 | ```js 61 | var a = 100; 62 | function print() { 63 | var a = 10; 64 | console.log(a); 65 | } 66 | print(); // 10 67 | ``` 68 | 69 | print 함수 앞에 선언한 `a`와 print 함수 안에 선언한 `a`는 각자 다른 유효 범위를 갖습니다. 70 | `var a = 100;` 는 자바스크립트 전역 객체인 window에 추가가 되고 `var a = 10;`는 `print()` 함수 안에서만 유효한 범위를 갖습니다. 71 | 72 | ## for 반복문에서의 var 유효 범위 73 | 74 | 위의 예제를 보다보면 흔히 헷갈릴 수 있는 부분이 "var의 유효 범위가 {}에 제한되나?" 입니다. 아래 예제를 살펴보겠습니다. 75 | 76 | ```js 77 | var a = 10; 78 | for (var a = 0; a < 5; a++) { 79 | console.log(a); // 0 1 2 3 4 5 80 | } 81 | console.log(a); // 6 82 | ``` 83 | 84 | `var a = 10;`로 변수 a를 선언한 상태에서 for 반복문에 동일한 변수 이름 a를 사용했습니다. 이렇게 되면 `{}` 으로 변수의 유효 범위가 제한되지 않기 때문에 for 반복문이 끝나고 나서 `console.log(a);` 를 출력하면 for 반복문의 마지막 결과 값이 출력됩니다. 아마 자바나 다른 언어의 개발자들에게는 이 부분이 가장 헷갈릴 것입니다. 85 | 86 | 이러한 문제점을 해결하고 다른 언어와 통일감을 주기 위해 ES6에서는 const와 let의 변수 유효 범위를 블록`{}`으로 제한하였습니다. 87 | 88 | ## const와 let의 블록 유효범위 89 | 90 | 이번엔 위 반복문 코드에 var 대신 let을 적용해보겠습니다. 91 | 92 | ```js 93 | var a = 10; 94 | for (let a = 0; a < 5; a++) { 95 | console.log(a); // 0 1 2 3 4 5 96 | } 97 | console.log(a); // 10 98 | ``` 99 | 100 | 반복문의 조건 변수 a를 let으로 선언하니 변수의 유효 범위가 for 반복문의 {} 블록 안으로 제한되었습니다. -------------------------------------------------------------------------------- /docs/es6+/default-parameter.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Default parameter 3 | --- 4 | 5 | # 기본값 매개변수(Default parameter) 6 | 7 | 기본값 매개변수란 함수의 매개변수에 값이 전달되지 않았을 때 기본 값으로 설정하는 문법입니다. 8 | 9 | ## 구문 10 | 11 | 기본값 매개변수의 문법은 다음과 같습니다. 12 | 13 | ```js 14 | function functionName(param1 = defaultValue1, ..., paramN = defaultValueN) { 15 | // ... 16 | } 17 | ``` 18 | 19 | 함수를 정의할 때 매개변수의 우측에 = 를 추가하고 함수에 값이 전달되지 않았을 때 설정할 기본 값을 defaultValue 위치에 지정합니다. 이 문법을 이용해 실제로 기본값 매개변수를 적용한 코드를 보겠습니다. 20 | 21 | ```js {1} 22 | function foo(param1 = 1, param2 = {}, param3 = 'korean') { 23 | console.log(param1, param2, param3); 24 | }; 25 | 26 | foo(30, { name: 'amy' }, 'american'); // 30, { name: 'amy' }, 'american' 27 | foo(); // 1, {}, 'korean' 28 | ``` 29 | 30 | ## 설명 31 | 32 | ES6 이전 문법에서는 or 연산자인 ||를 이용하여 입력받은 파라미터를 지역변수에 재정의하는 방식을 사용하였습니다. or 연산자의 특성으로 인하여 파라미터의 값이 [falsy value(false 로 평가되는 값, false, null, 0, undefined...)](https://developer.mozilla.org/ko/docs/Glossary/Falsy) 인 경우에 || 연산자 우항의 값을 기본값으로 사용하게 됩니다. 33 | 34 | ### || 를 이용한 기본값 할당 방식 35 | 36 | ```js {2-4} 37 | function printPersonInfo(height, weight, age) { 38 | var height = height || 180; 39 | var weight = weight || 60; 40 | var age = age || 66; 41 | 42 | console.log(height, weight, age); 43 | }; 44 | 45 | printPersonInfo(10, 200, 300); // 10, 200, 300 46 | printPersonInfo(); // 180, 100, 66 47 | ``` 48 | 49 | 기본값 매개변수를 사용하면 더는 함수 내부에서 값을 비교하고 할당하는 연산이 필요하지 않습니다.
50 | 간단하게 함수의 매개변수를 선언하는 곳에서 기본값을 미리 정의 할 수 있습니다. 51 | 52 | ### 기본값 매개변수 사용 방식 53 | 54 | ```js {1} 55 | function printPersonInfo(height = 180, weight = 60, age = 66) { 56 | console.log(height, weight, age); 57 | }; 58 | 59 | printPersonInfo(178, 58, 29); // 178, 58, 29 60 | printPersonInfo(100); // 100, 60, 66 61 | ``` 62 | 63 | ## 주의사항 64 | 65 | 하지만 ES6의 기본값 매개변수는 파라미터가 정의되지 않고 `undefined` 값인 경우에만 기본 값을 할당합니다.
66 | 따라서, || 연산자를 통한 지역변수 재정의 방식과는 그 동작이 다르므로, 예전 문법에 익숙한 경우 주의해서 사용하여야 합니다.
아래 예시 코드로 좀 더 상세히 알아보겠습니다. 67 | 68 | ```js 69 | // || 를 이용한 기본값 방식 70 | function printFruit(name, weight, price) { 71 | var name = name || 'apple'; 72 | var weight = weight || 10; 73 | var price = price || 15000; 74 | 75 | console.log(name, weight, price); 76 | }; 77 | 78 | printFruit(0, false, null); // apple, 10, 15000 79 | 80 | 81 | // 기본값 매개변수 사용 방식 82 | function printFruit(name = 'apple', weight = 10, price = 15000) { 83 | console.log(name, weight, price); 84 | }; 85 | 86 | // 0, false, null을 값으로 인식하여 기본값 대체되지 않음 87 | printFruit(0, false, null); // 0, false, null 88 | // 값이 없거나 undefined 일 때 기본값으로 대체 89 | printFruit(); // apple, 10, 15000 90 | ``` 91 | -------------------------------------------------------------------------------- /docs/es6+/enhanced-object-literals.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Enhanced Object Literal 3 | --- 4 | 5 | # 향상된 객체 리터럴(Enhanced Object Literal) 6 | 7 | 향상된 객체 리터럴이란 기존 자바스크립트에서 사용하던 객체 정의 방식을 개선한 문법입니다. 자주 사용하던 문법들을 좀 더 간결하게 사용할 수 있도록 객체 정의 형식을 바꿨습니다. 8 | 9 | ## 기존 객체 정의 방식 10 | 11 | 기존 자바스크립트의 객체 정의 방식은 다음과 같습니다. 12 | 13 | ```js 14 | var josh = { 15 | // 속성: 값 16 | language: 'javascript', 17 | coding: function() { 18 | console.log('Hello World'); 19 | } 20 | }; 21 | ``` 22 | 23 | ## 축약 문법 1 - 속성과 값이 같으면 1개만 기입 24 | 25 | 객체를 정의할 때 속성(property)와 값(value)이 같으면 아래와 같이 축약이 가능합니다. 26 | 27 | ```js 28 | var language = 'javascript'; 29 | 30 | var josh = { 31 | // language: language, 32 | language 33 | }; 34 | 35 | console.log(josh); // {language: "javascript"} 36 | ``` 37 | 38 | 위와 같은 축약 문법을 뷰 컴포넌트 등록 방식과 뷰 라우터 등록 방식에 대입해보면 아래와 같습니다. 39 | 40 | ```js 41 | // #1 - 컴포넌트 등록 방식에서의 축약 문법 42 | const myComponent = { 43 | template: '

My Component

' 44 | }; 45 | 46 | new Vue({ 47 | components: { 48 | // myComponent: myComponent 49 | myComponent 50 | } 51 | }); 52 | ``` 53 | 54 | ```js 55 | // #2 - 라우터 등록 방식에서의 축약 문법 56 | const router = new VueRouter({ 57 | // ... 58 | }); 59 | 60 | new Vue({ 61 | // router: router, 62 | router 63 | }); 64 | ``` 65 | 66 | ## 축약 문법 2 - 속성에 함수를 정의할 때 function 예약어 생략 67 | 68 | 기존에 객체를 정의할 때 객체의 속성에 함수를 연결하여 사용하는 경우가 많았습니다. 예를 들면 아래와 같이 말이죠. 69 | 70 | ```js 71 | const josh = { 72 | // 속성: 함수 73 | coding: function() { 74 | console.log('Hello World'); 75 | } 76 | }; 77 | josh.coding(); // Hello World 78 | ``` 79 | 80 | 실제로 기능을 구현하다보면 위와 같이 정의해야 할 때가 너무 많습니다. 따라서, ES6에서는 아래와 같이 축약하여 코딩하는 것을 추천합니다. 81 | 82 | ```js 83 | const josh = { 84 | coding() { 85 | console.log('Hello World'); 86 | } 87 | }; 88 | josh.coding(); // Hello World 89 | ``` 90 | 91 | 이렇게 `function` 예약어를 생략해도 동일하게 동작하기 때문에 타이핑 하는 시간이 줄어듭니다. 92 | 93 | 그럼 이번에는 뷰 코드에 적용해서 얼마나 타이핑이 줄어드는지 확인해볼까요? 94 | 95 | ```js 96 | new Vue({ 97 | // ... 98 | methods: { 99 | fetchData: function() { 100 | // ... 101 | }, 102 | showAlert: function() { 103 | // ... 104 | } 105 | } 106 | }); 107 | ``` 108 | 109 | 위의 코드를 아래와 같이 생략할 수 있습니다. 110 | 111 | ```js 112 | new Vue({ 113 | // ... 114 | methods: { 115 | fetchData() { 116 | // ... 117 | }, 118 | showAlert() { 119 | // ... 120 | } 121 | } 122 | }); 123 | ``` -------------------------------------------------------------------------------- /docs/es6+/modules.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Modules 3 | --- 4 | 5 | # Import & Export 6 | 7 | 임포트(Import)와 익스포트(Export)는 자바스크립트의 코드를 모듈화 할 수 있는 기능입니다. 여기서 모듈화란 쉽게 말해서 다른 파일에 있는 자바스크립트의 기능을 특정 파일에서 사용할 수 있는 것을 의미합니다. 8 | 9 | ## 모듈화의 필요성 10 | 11 | 기본적으로 자바스크립트의 유효 범위는 전역으로 시작합니다. 따라서 아래와 같이 HTML 페이지를 로딩하면 원하는 결과가 나오지 않습니다. 12 | 13 | ```html 14 | 15 | 16 | 17 | 18 | 21 | 22 | ``` 23 | 24 | ```js 25 | // a.js 26 | var total = 100; 27 | function getTotal() { 28 | return total; 29 | } 30 | ``` 31 | 32 | ```js 33 | // b.js 34 | var total = 200; 35 | ``` 36 | 37 | 다른 프로그래밍 언어 배경을 가지신 분들이라면 파일 마다 변수의 유효 범위가 다를 것이라고 생각합니다. 하지만 자바스크립트는 기본적으로 변수의 유효 범위가 전역으로 잡히기 때문에 네임스페이스 모듈화 패턴이나 [Require.js](https://requirejs.org/)와 같은 모듈화 라이브러리를 이용하여 모듈화 기능을 구현해왔습니다. 38 | 39 | 이제는 프로그래밍 패턴이나 별도의 모듈화 라이브러리를 사용하지 않고도 자바스크립트 언어 자체에서 모듈화를 지원합니다. 40 | 41 | ## import & export 기본 문법 42 | 43 | 모듈화 기능을 사용하기 위한 기본적인 import, export 문법을 보겠습니다. 44 | 45 | 먼저 export 문법입니다. 46 | 47 | ```js 48 | export 변수, 함수 49 | ``` 50 | 51 | 다른 파일에서 가져다 쓸 변수나 함수의 앞에 `export` 라는 키워드를 붙입니다. 익스포트된 파일은 임포트로 불러와 사용할 수 있습니다. 52 | 53 | import 문법을 보겠습니다. 54 | 55 | ```js 56 | import { 불러올 변수 또는 함수 이름 } from '파일 경로'; 57 | ``` 58 | 59 | 익스포트된 변수나 함수를 `{}`에 선언한 뒤 해당 파일이 있는 경로를 적어줍니다. 60 | 61 | ## import & export 기본 예제 62 | 63 | 배운 문법을 바탕으로 간단한 예제를 살펴보겠습니다. 64 | 65 | ```js 66 | // math.js 67 | export var pi = 3.14; 68 | ``` 69 | 70 | ```js 71 | // app.js 72 | import { pi } from './math.js'; 73 | 74 | console.log(pi); // 3.14 75 | ``` 76 | 77 | 위 코드는 `math.js`라는 파일에서 `pi`를 익스포트하고 `app.js` 파일에서 임포트하여 콘솔에 출력하는 코드입니다. 만약 변수가 아니라 함수를 내보내고 싶다면 아래와 같이 코딩할 수 있습니다. 78 | 79 | ```js {3-5} 80 | // math.js 81 | export var pi = 3.14; 82 | export function sum(a, b) { 83 | return a + b; 84 | } 85 | ``` 86 | 87 | ```js 88 | // app.js 89 | import { sum } from './math.js'; 90 | 91 | sum(10, 20); // 30 92 | ``` 93 | 94 | 위 코드는 `math.js`에 두 숫자의 합을 구하는 `sum()` 함수를 익스포트 한 뒤 `app.js`에서 임포트하여 사용한 코드입니다. 95 | 96 | ## 브라우저 지원 범위 97 | 98 | ES6의 기본적인 문법들이 최신 브라우저에서 지원되는데 반해 import, export는 아직 보조 도구가 있어야만 사용할 수 있습니다. 브라우저 지원 범위는 [여기](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/export#Browser_compatibility)를 확인하세요. 99 | 100 | 가급적 실무 코드에서 사용하실 때는 [웹팩(Webpack)](https://webpack.js.org/)과 같은 모듈 번들러를 이용하여 구현하는 것을 추천드립니다. -------------------------------------------------------------------------------- /docs/es6+/nullish-coalescing-operator.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Nullish coalescing operator 3 | --- 4 | 5 | # Nullish coalescing operator(`??`) 6 | 7 | 널 병합 연산자(Nullish coalescing operator)는 연산자(`??`)의 왼쪽 피연산자가 null 또는 undefined일 때 오른쪽 피연산자를 반환하고, 그렇지 않으면 왼쪽 피연산자를 반환하는 논리 연산자입니다. 8 | 9 | ## 기존 문자열 할당 방식 10 | 11 | 기존 함수의 인자가 null 또는 undefined인 경우를 판단하는 방식은 아래와 같았습니다. 12 | 13 | ```js 14 | function printTitle(text) { 15 | let title = text; 16 | if (text == null || text == undefined) { 17 | title = 'Cracking Vue.js'; 18 | } 19 | console.log(title); 20 | } 21 | 22 | printTitle('Crack'); // Crack 23 | printTitle(); // Cracking Vue.js 24 | ``` 25 | 26 | ## 널 병합 연산자를 이용한 방식 27 | 28 | 널 병합 연산자(`??`)를 이용한 위 예제 코드의 함수 정의 방식은 아래와 같습니다. 29 | 30 | ```js 31 | function printTitle(text) { 32 | let title = text ?? 'Cracking Vue.js'; 33 | console.log(title); 34 | } 35 | 36 | printTitle('Crack'); // Crack 37 | printTitle(); // Cracking Vue.js 38 | ``` 39 | 40 | 위 코드를 보시면 기존의 if 문을 활용해서 null 또는 undefined인 경우를 판단했던 방식보다 널 병합 연산자(`??`)를 사용했을 때 코드의 양이 줄어들고, 훨씬 간결해진 것을 확인하실 수 있습니다. 41 | 42 | ## 논리 연산자 OR(`||`)와의 차이점 43 | 44 | 널 병합 연산자(`??`)와 비슷한 논리 연산자 OR(`||`)가 있습니다. 논리 연산자 OR(`||`) 또한 왼쪽의 피연산자가 null 또는 undefined인 경우 오른쪽의 피연산자를 반환합니다. 45 | 46 | 하지만 논리 연산자 OR(`||`)는 null과 undefined를 포함한 [falsy](https://developer.mozilla.org/en-US/docs/Glossary/Falsy) 한 값인 `0`, `''`, `NaN`의 경우에도 오른쪽 피연산자를 반환합니다. 47 | 48 | ```js 49 | function printTitle(text) { 50 | const title = text || 'Cracking Vue.js'; 51 | console.log(title); 52 | } 53 | 54 | printTitle('Crack'); // Crack 55 | printTitle(); // Cracking Vue.js 56 | ``` 57 | 58 | 논리 연산자 OR(`||`)는 `0`, `''`, `NaN` 과 같은 값을 유효한 값이라고 생각한 경우에는 문제가 발생합니다. 59 | 60 | 이런 문제가 발생했을 때 널 병합 연산자(`??`)를 사용하면 간단하게 해결할 수 있습니다. 61 | 62 | ```js 63 | function getCount(count) { 64 | return count || 'There is no record.'; 65 | } 66 | 67 | getCount(0); // There is no record. 68 | getCount(1); // 1 69 | ``` 70 | 71 | ::: tip 72 | 널 병합 연산자(`??`)와 논리 연산자 OR(`||`)를 상황에 따라 적절하게 사용하시면 아주 좋습니다. 73 | ::: 74 | -------------------------------------------------------------------------------- /docs/es6+/optional-chaning.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Optional Chaning 3 | --- 4 | 5 | # Optional Chaning(`?.`) 6 | 7 | 옵셔널 체이닝은 ES2020에 추가된 자바스크립트 문법입니다. 타입스크립트 `3.7` 버전에서 구현된 기능이기 때문에 타입스크립트를 사용하셨던 분들에겐 익숙한 문법일 것 입니다. 옵셔널 체이닝 문법으로 객체의 속성 값이 유효한지 검증할 수 있습니다. 옵셔널 체이닝(`?.`) **앞**의 평가 대상이 `undefined`나 `null`이면 에러가 발생하지 않고 `undefined` 를 반환합니다. 8 | 9 | ## 옵셔널 체이닝이 추가되기 전 10 | 11 | 옵셔널 체이닝 문법이 추가되기 전에 중첩된 객체의 하위 속성을 찾기 위한 코드는 아래와 같았습니다. 12 | 13 | ```js 14 | const userInfo = { 15 | name: { 16 | first: 'Hong', 17 | last: 'Gildong', 18 | }, 19 | address: { 20 | city: 'Seoul', 21 | postcode: '04377', 22 | }, 23 | }; 24 | 25 | const postcode = userInfo.address && userInfo.address.postcode; 26 | ``` 27 | 28 | `&&` 연산자를 사용해서 `userInfo` 에 `address` 속성이 있는지 확인을 하고 `postcode` 에 접근하는 것을 볼 수 있습니다. 29 | 30 | ## 옵셔널 체이닝이 추가 된 후 31 | 32 | ```js 33 | const userInfo = { 34 | name: { 35 | first: 'Hong', 36 | last: 'Gildong', 37 | }, 38 | address: { 39 | city: 'Seoul', 40 | postcode: '04377', 41 | }, 42 | }; 43 | 44 | const postcode = userInfo.address?.postcode; 45 | ``` 46 | 47 | 옵셔널 체이닝을 사용하면 이전 코드보다 문법적으로 깔끔하고 안전하게 중첩된 객체의 하위 속성 값에 접근할 수 있습니다. 48 | 49 | ```js 50 | const userInfo = { 51 | name: { 52 | first: 'Hong', 53 | last: 'Gildong', 54 | }, 55 | address: { 56 | city: 'Seoul', 57 | postcode: '04377', 58 | }, 59 | getInfo: () => userInfo, 60 | }; 61 | 62 | userInfo.getInfo?.(); 63 | // userInfo object 64 | 65 | userInfo.setInfo?.(); 66 | // undefined 67 | ``` 68 | 69 | 옵셔널 체이닝은 메소드의 존재 여부를 확인하고 호출할 때도 사용할 수 있습니다. 70 | 71 | ```js 72 | const userInfo = { 73 | name: { 74 | first: 'Hong', 75 | last: 'Gildong', 76 | }, 77 | address: { 78 | city: 'Seoul', 79 | postcode: '04377', 80 | }, 81 | }; 82 | const key = 'city'; 83 | 84 | console.log(userInfo.address?.[key]); 85 | // Seoul 86 | ``` 87 | 88 | `.` 대신 대괄호 `[]` 를 사용해 객체의 속성에 접근하는 경우에도 옵셔널 체이닝을 사용할 수 있습니다. 89 | 90 | ## 널 병합 연산자(`??`)와 같이 활용하기 91 | 92 | 옵셔널 체이닝과 널 병합 연산자(`??`)를 사용하여 특정 속성의 값의 유무를 판별하고 기본 값을 정의할 수 있습니다. 93 | 94 | ```js 95 | const userInfo = { 96 | name: { 97 | first: 'Hong', 98 | last: 'Gildong', 99 | }, 100 | address: { 101 | city: 'Seoul', 102 | postcode: '04377', 103 | }, 104 | }; 105 | 106 | const city = userInfo.address?.city ?? 'New York'; 107 | ``` 108 | 109 | 위 코드에서 `city`의 값은 널 병합 연산자(`??`)의 왼쪽 항인 옵셔널 체이닝으로 검증한 객체의 속성 값이 `null`또는 `undefined`이면 널 병합 연산자(`??`)의 오른쪽 항인 `New York`이 기본 값으로 적용됩니다. 110 | 111 | ::: tip 112 | 널 병합 연산자(`??`)에 대한 자세한 내용은 [널 병합 연산자(`??`) 포스팅](/es6+/nullish-coalescing-operator.html)을 참고하세요. 113 | ::: 114 | 115 | ::: warning 116 | 옵셔널 체이닝을 남용하지 않도록 주의해주세요. 117 | ::: 118 | 119 | 옵셔널 체이닝(`?.`)은 존재하지 않아도 괜찮은 대상에만 사용해야 합니다. 위 예제 코드에서 `userInfo`는 반드시 존재해야 하지만 `address`는 필수값이 아닙니다. 그러므로 `userInfo.address?.city` 이렇게 사용하는 것은 바람직하지만 `userInfo?.address?.city` 는 바람직하지 않습니다. 이렇게 사용하게 된다면 `userInfo`의 값이 올바르지 않을 때 즉시 에러를 발생시키지 못해 추후 디버깅에 어려움을 겪을 수 있습니다. 120 | -------------------------------------------------------------------------------- /docs/es6+/spread-operator.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Spread Operator 3 | --- 4 | 5 | # 스프레드 오퍼레이터(Spread Operator) 6 | 7 | 스프레드 오퍼레이터는 한글로 번역해보면 펼침 연산자 정도로 볼 수 있습니다. 스프레드 오퍼레이터는 특정 객체 또는 배열의 값을 다른 객체, 배열로 복제하거나 옮길 때 사용합니다. 연산자의 모양은 `...` 이렇게 생겼습니다. 8 | 9 | ## 스프레드 오퍼레이터 사용법 10 | 11 | 바로 한번 코드로 살펴볼까요? 12 | 13 | ```js 14 | // obj 객체를 newObj 객체에 복제 15 | var obj = { 16 | a: 10, 17 | b: 20 18 | }; 19 | var newObj = {...obj}; 20 | console.log(newOjb); // {a: 10, b: 20} 21 | 22 | // arr 배열을 newArr 배열에 복제 23 | var arr = [1,2,3]; 24 | var newArr = [...arr]; 25 | console.log(newArr); // [1, 2, 3] 26 | ``` 27 | 28 | 위 코드들은 모두 스프레드 오퍼레이터를 이용하여 특정 객체, 배열의 값을 각각 새로운 객체와 배열에 복제하는 코드입니다. 이렇게 스프레드 오퍼레이터를 사용하는 이유는 무엇일까요? 29 | 30 | ## 기존 자바스크립트의 객체 복제 방식 31 | 32 | 앞에서 살펴본 코드에서 스프레드 오퍼레이터를 사용하지 않고 기존 자바스크립트 문법으로만 구현해보겠습니다. 33 | 34 | ```js 35 | // 객체의 값을 복사하는 경우 36 | var obj = { 37 | a: 10, 38 | b: 20 39 | }; 40 | var newObj = { 41 | a: obj.a, 42 | b: obj.b 43 | }; 44 | console.log(newObj); // {a: 10, b: 20} 45 | 46 | // 배열의 값을 복사하는 경우 47 | var arr = [1,2,3]; 48 | var newArr = [arr[0], arr[1], arr[2]]; 49 | console.log(newArr); // [1, 2, 3] 50 | ``` 51 | 52 | 객체를 복사하는 경우, 새로운 객체인 `newObj`에 새로운 속성들을 선언하고 각 속성에 `obj`의 속성들을 일일이 접근해서 대입해줘야 합니다. 배열 `newArr`의 경우에는 기존 배열 `arr`의 인덱스에 일일이 접근하여 새로운 요소를 만들어줘야 합니다. 53 | 54 | 위 코드에서 살펴볼 수 있듯이 스프레드 오퍼레이터를 사용하게 되면 타이핑해야 하는 코드의 양이 확연히 줄어듭니다. 55 | 56 | ## 뷰엑스에 적용해본 스프레드 오퍼레이터 57 | 58 | 뷰에서 스프레드 오퍼레이터가 가장 잘 활용되는 부분은 뷰엑스(Vuex)의 헬퍼 함수입니다. 뷰엑스와 헬퍼 함수가 익숙하지 않은 분들은 [Vuex 시작하기 2](https://joshua1988.github.io/web-development/vuejs/vuex-getters-mutations/)글을 참고하세요. 어차피 여기서 중요한 부분은 스프레드 오퍼레이터가 어떤 식으로 뷰에서 활용되는지 확인하는 것입니다. 59 | 60 | 그럼 코드를 살펴보겠습니다. 61 | 62 | ```js 63 | import { mapGetters } from 'vuex'; 64 | 65 | export default { 66 | computed: { 67 | ...mapGetters(['getStrings', 'getNumbers', 'getUsers']), 68 | anotherCounter() { 69 | // .. 70 | } 71 | } 72 | } 73 | ``` 74 | 75 | 위 코드에서 `mapGetters`라는 헬퍼 함수 앞에 스프레드 오퍼레이터인 `...`를 사용하였습니다. 만약 `...`를 사용하지 않았다면, computed 속성 함수에는 뷰엑스의 getters 속성 함수들만 정의할 수 있었을 것입니다. 무슨 말인지 이해가 안가신다구요? 그럼 위의 코드에서 `...`를 더 풀어볼게요. 76 | 77 | ```js 78 | import { mapGetters } from 'vuex'; 79 | 80 | export default { 81 | computed: { 82 | getStrings() { 83 | // .. 84 | }, 85 | getNumbers() { 86 | // .. 87 | }, 88 | getUsers() { 89 | // .. 90 | }, 91 | anotherCounter() { 92 | // .. 93 | } 94 | } 95 | } 96 | ``` 97 | 98 | 만약 `...`를 쓰지 않았다면 `anotherCounter()`를 추가로 정의할 수 없었을 것입니다. `...`로 풀어서 위와 같이 삽입을 해줬기 때문에 추가로 computed 속성 함수를 정의할 수 있게 되었습니다. -------------------------------------------------------------------------------- /docs/es6+/template-literal.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Template Literal 3 | --- 4 | 5 | # 템플릿 리터럴(Template Literal) 6 | 7 | 템플릿 리터럴이란 자바스크립트에서 문자열을 입력하는 방식입니다. 기존에는 `var str = 'Hello ES6'`와 같은 방식으로 사용하였으나 ES6에서는 백틱(back-tick)이라는 기호(\`)를 사용하여 정의합니다. 8 | 9 | ```js 10 | const str = `Hello ES6`; 11 | ``` 12 | 13 | 위와 같이 백틱을 이용하게 되면 여러 줄에 걸쳐 문자열을 정의할 수도 있고, 자바스크립트의 변수를 문자열 안에 바로 연결할 수 있는 이점이 생깁니다. 14 | 15 | ## 여러 줄에 걸쳐 문자열 선언하기 16 | 17 | 기존 자바스크립트의 문자열 선언 방식인 작은 따옴표(')의 문제점은 아래와 같았습니다. 18 | 19 | ```js 20 | var str = 'Template literals are string literals allowing embedded expressions. \n' + 21 | 'You can use multi-line strings and string interpolation features with them. \n' + 22 | 'They were called "template strings" in prior editions of the ES2015 specification.'; 23 | ``` 24 | 25 | 작은 따옴표를 이용하여 긴 문자열을 선언하게 되면 자동으로 개행이 되지 않기 때문에 라인 브레이커(line breaker)인 `\n`를 개행할 곳 중간 중간에 추가해야 했습니다. 이렇게 되면 문장이 길면 길수록 `+`와 `\n`를 계속 추가해줘야 하는 번거로움이 생깁니다. 26 | 27 | 백틱을 이용해서 문자열을 선언하게 되면 위와 같이 개행할 필요가 없습니다. 28 | 29 | ```js 30 | const str = `Template literals are string literals allowing embedded expressions. 31 | You can use multi-line strings and string interpolation features with them. 32 | They were called "template strings" in prior editions of the ES2015 specification.`; 33 | ``` 34 | 35 | 그럼 뷰에서는 위의 문법을 어떻게 적용할 수 있을까요? CDN 방식으로 뷰를 적용할 때 컴포넌트의 template 속성에 적용하면 좋습니다. 아래와 같이 말입니다. 36 | 37 | ```js 38 | Vue.component('my-cmp', { 39 | template: ` 40 |
41 |

My Component

42 |

back-tick is useful

43 |
44 | ` 45 | }); 46 | ``` 47 | 48 | ## 문자열 중간에 변수 바로 대입하기 49 | 50 | 기존 문자열 정의 방식에서 또 번거로웠던 부분은 바로 자바스크립트 변수 값을 문자열과 함께 사용하는 부분이었습니다. 51 | 52 | ```js 53 | var language = 'Javascript'; 54 | var expression = 'I love ' + language + '!'; 55 | console.log(expression); // I love Javascript! 56 | ``` 57 | 58 | 위와 같이 문자열에 특정 변수의 값을 함께 사용하려면 `+`를 이용하여 문자열 중간에 해당 변수를 연결해줘야 했습니다. 59 | 60 | ES6에서는 템플릿 리터럴을 이용하면 아래와 같이 간편하게 문자열과 변수를 함께 사용할 수 있습니다. 61 | 62 | ```js 63 | var language = 'Javascript'; 64 | var expression = `I love ${language}!`; 65 | console.log(expression); // I love Javascript! 66 | ``` 67 | 68 | `${}`를 이용하면 위와 같이 변수의 값을 대입할 수 있을 뿐만 아니라 간단한 연산도 할 수 있습니다. 69 | 70 | ```js 71 | var language = 'Javascript'; 72 | var expression = `I love ${language.split('').reverse().join('')}!`; 73 | console.log(expression); // I love tpircsavaJ! 74 | ``` 75 | 76 | 위 코드는 `language`의 문자열 순서를 역으로 바꾸는 코드입니다. -------------------------------------------------------------------------------- /docs/format/cli-questions.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/joshua1988/vue-camp/1d2b5ed08f37e891e5dd2c762a9cc25d2351a9dc/docs/format/cli-questions.png -------------------------------------------------------------------------------- /docs/format/format-on-save.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/joshua1988/vue-camp/1d2b5ed08f37e891e5dd2c762a9cc25d2351a9dc/docs/format/format-on-save.png -------------------------------------------------------------------------------- /docs/format/img/husky-prettier-error.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/joshua1988/vue-camp/1d2b5ed08f37e891e5dd2c762a9cc25d2351a9dc/docs/format/img/husky-prettier-error.png -------------------------------------------------------------------------------- /docs/format/official.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: ESLint & Prettier 3 | --- 4 | 5 | # ESLint와 Prettier 설정 하기 6 | 7 | 팀 프로젝트에서 뷰를 개발할 때 코드를 일관적으로 작성하고 에러를 덜 나게 하는 방법이 있습니다. 8 | 바로 ESLint + Prettier 플러그인을 사용하는 방법인데요. 9 | 이 2개 도구에 대한 자세한 설명과 설정 방법은 다음 글을 참고합니다. 10 | 11 | - [Vue.js 개발 생산성을 높여주는 도구 3가지](https://joshua1988.github.io/web-development/vuejs/boost-productivity/) 12 | 13 | ## Vite 기반 Vue 3 프로젝트에서의 ESLint와 Prettier 설정 방법 14 | 15 | Vue 3 공식 문서의 프로젝트 스캐폴딩(초기 환경 구성) 페이지에 안내된 프로젝트 생성 방법입니다. 16 | 17 | ```sh 18 | npm init vue@latest 19 | ``` 20 | 21 | 이 명령어를 입력하면 Vite 기반의 프로젝트가 생성됩니다. 프로젝트가 생성될 때 프로젝트 이름, 타입스크립트 설정 등을 묻는 9개의 질문이 나옵니다. 각 질문을 아래와 같이 답합니다. 22 | 23 | ![vue-vite-cli-questions.png](./cli-questions.png) 24 | 25 | 생성된 프로젝트로 이동한 후 터미널(명령어 프롬프트 창)에 안내된 NPM 설치 명령어를 실행합니다. 설치가 완료된 후 VSCode의 설정에서 `Format on Save` 옵션을 켭니다. 26 | 27 | ![format-on-save](./format-on-save.png) 28 | 29 | 마지막으로 main.js 파일에서 `mount('#app')` 코드 끝에 세미 콜론을 붙이고 파일을 저장하면 프리티어 규칙에 따라 세미 콜론이 자동으로 사라지는 것을 볼 수 있습니다. 30 | 31 | ::: tip 32 | 코드 포맷팅에 대한 자세한 설정은 [프리티어 공식 문서](https://prettier.io/docs/en/options.html)의 내용과 [Vue.js 개발 생산성을 높여주는 도구 3가지](https://joshua1988.github.io/web-development/vuejs/boost-productivity/) 문서를 참고하세요. 33 | ::: 34 | -------------------------------------------------------------------------------- /docs/format/prettier.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Prettier 3 | --- 4 | 5 | # Prettier 설정 하기 6 | 7 | 협업 시, 에러를 줄이고 일관적인 코드를 작성하기 위해 코드 포맷터 프리티어(Prettier)를 사용하는 방법이 있습니다. 8 | Prettier를 프로젝트에 세팅하는 방법과 commit 전에 전체 코드를 대상으로 prettier를 실행해서 포맷팅 후에 commit을 하도록 하는 방법에 대해 알아보겠습니다. 9 | 10 | ## 포맷팅할 prettier 설정파일 생성하기 11 | 12 | 프로젝트 루트 디렉토리에서 `.prettierrc` 생성합니다. 13 | 14 | ```json 15 | { 16 | "singleQuote": true, 17 | "semi": true, 18 | "useTabs": false, 19 | "tabWidth": 2, 20 | "trailingComma": "all", 21 | "printWidth": 120, 22 | "parser": "babel", 23 | "bracketSpacing": true, 24 | "arrowParens": "avoid" 25 | } 26 | ``` 27 | 28 | :::tip 29 | 각 옵션에 대해 자세히 알고 싶다면 [prettier 공식 사이트](https://prettier.io/docs/en/options.html)를 참고하세요. 30 | ::: 31 | 32 | ## vscode에서 prettier 설치 및 실행하기 33 | 34 | 1. Extensions(mac : `command + shift + x`, window : `control + shift + x`)에서 Prettier를 설치합니다. 35 | 36 | 2. 설치가 완료되면 command + p를 누르고 `> Format Document`를 실행합니다. 37 | 38 | ## vscode에서 저장(command + s)시 자동으로 prettier 실행하기 39 | 40 | 1. command + ,를 누르고 검색에 `format on save`를 입력합니다. 41 | 42 | 2. `Editor: Format on Save`를 체크하고 vscode를 재부팅합니다. 43 | 44 | 3. 만약 저장시 포맷팅이 안된다면 다시 `command + ,`를 누르고 검색창에 `default formatter`를 검색하고 none으로 되어 있으면 Prettier - Code formatter로 변경 후 재부팅합니다. 45 | 46 | ## husky를 사용하여 commit 전에 prettier 전체 파일에 적용하기 47 | 48 | 허스키(husky)를 사용하면 Prettier를 설치하지 않아도 commit 전에 lint-staged에 설정된 파일 중에 변경된 파일을 대상으로 자동으로 포맷팅하여 commit 합니다. 49 | 50 | :::tip 51 | husky는 git hook을 쉽게 관리할 수 있는 도구입니다. git push, commit 등이 시행되기 전이나 후에 원하는 스크립트를 실행시켜줍니다. 52 | 더 자세한 내용을 알고 싶다면 [husky 공식 사이트](https://typicode.github.io/husky/)를 참고하세요. 53 | ::: 54 | 55 | 1. 위에서 설명드린 `포맷팅할 prettier 설정파일 생성하기`을 만듭니다. 56 | 57 | 2. 관련 라이브러리를 설치합니다. 58 | 59 | ```sh 60 | yarn add -D husky@4 lint-staged prettier 61 | ``` 62 | 63 | 3. package.json에 아래와 같이 추가합니다. 64 | 65 | ```json 66 | { 67 | ... 68 | "scripts": { 69 | ... 70 | "init-husky": "npx husky install .husky", 71 | "lint-front": "lint-staged" 72 | }, 73 | "lint-staged": { 74 | // 변경된 js, vue, json, md 파일을 대상으로 prettier를 실행합니다. 75 | "src/**/*.{js,json,md}": [ 76 | "prettier --write", 77 | "git add" 78 | ] 79 | }, 80 | } 81 | 82 | ``` 83 | 84 | 4. husky를 설치합니다. 85 | 86 | ```bash 87 | yarn init-husky 88 | ``` 89 | 90 | 이후 생성된 `.husky` 파일 하위에 `pre-commit`이라는 파일을 하나 생성하고 아래 코드를 넣습니다. 91 | 92 | ```bash 93 | #!/bin/sh 94 | . "$(dirname "$0")/_/husky.sh" 95 | 96 | yarn lint-front 97 | 98 | ``` 99 | 100 | 5. 이후 다른 파일을 변경하고 commit 하면 파일이 포맷팅 되어 commit 되는지 확인합니다. 101 | 102 | 6. 만약 아래와 같은 에러로 commit이 실패 한다면 터미널에 아래 코드를 넣습니다. 103 | 104 | ![husky 에러](./img/husky-prettier-error.png) 105 | 106 | 깃 훅 실행 권한을 부여하는 코드입니다. 107 | 108 | ```sh 109 | chmod ug+x ./husky/* 110 | chmod ug+x .git/hooks/* 111 | ``` 112 | 113 | 7. vscode를 재부팅하고 다시 파일을 변경하여 commit 합니다. 114 | -------------------------------------------------------------------------------- /docs/js/array.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Array 3 | --- 4 | 5 | # 배열(Array) 6 | 7 | 배열(Array)은 객체와 더불어 실제로 웹 애플리케이션을 구현할 때 가장 많이 쓰이는 변수 타입입니다. 배열을 선언하는 방식은 객체와 유사합니다. 8 | 9 | ```js 10 | var arr = []; 11 | ``` 12 | 13 | 여기서 `[]`를 배열 리터럴이라고 하며 배열을 정의할 때 사용합니다. 14 | 15 | ## 배열의 요소 16 | 17 | 객체는 `속성 / 값`의 조합으로 데이터를 저장하지만 배열은 `인덱스 / 값`의 조합으로 데이터를 저장합니다. 18 | 19 | ```js 20 | // arr 변수에 빈 배열을 선언 21 | var arr = []; 22 | 23 | // 배열의 0번째 인덱스에 10을 대입 24 | arr[0] = 10; 25 | 26 | console.log(arr); // [10] 27 | ``` 28 | 29 | ::: tip 30 | 배열의 인덱스는 0부터 시작합니다. 빈 배열에 최초로 값을 추가하면 0번째 인덱스에 값이 추가됩니다. 31 | ::: 32 | 33 | ## 배열 조작하기 34 | 35 | 배열을 조작하는 방법은 아래와 같이 직접 인덱스에 접근해서 조작하는 방법이 있습니다. 36 | 37 | ```js 38 | // 인덱스를 직접 접근해서 사용하는 경우 39 | var arr = []; 40 | arr[0] = 100; 41 | arr[1] = 20; 42 | arr[0] = 10; 43 | console.log(arr); // [10, 20] 44 | ``` 45 | 46 | 하지만 위와 같이 인덱스에 직접 접근해서 조작하는 것보다 자바스크립트 내장 API를 사용하는 것을 추천합니다. 그리고 이 방식은 뷰 개발자 뿐만 아니라 자바스크립트 개발자들에게도 권장되는 방식입니다. 47 | 48 | ```js 49 | // 자바스크립트 내장 API를 사용하는 경우 50 | var arr = []; 51 | arr.push(100); // [100] 52 | arr.push(20); // [100, 20] 53 | arr.splice(0, 1, 10); // [10, 20] 54 | console.log(arr); // [10, 20] 55 | ``` 56 | 57 | ## 자주 사용하는 배열 API 58 | 59 | 배열을 조작할 때 주로 사용하는 API는 다음과 같습니다. 60 | 61 | - [push()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/push) : 배열에 데이터 추가 (맨 끝 인덱스부터 추가됨) 62 | - [slice()](https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Global_Objects/Array/slice) : 배열의 특정 인덱스에 있는 값을 반환 (배열의 내용이 변환되지 않음) 63 | - [splice()](https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Global_Objects/Array/splice) : 배열의 특정 인덱스에 있는 값을 변경 또는 삭제 (배열의 내용이 변경됨) 64 | - [pop()](https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Global_Objects/Array/pop) : 배열의 마지막 인덱스의 값을 꺼냄 (배열의 내용이 변경됨) 65 | - [shift()](https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Global_Objects/Array/shift) : 배열의 첫번째 인덱스의 값을 꺼냄 (배열의 내용이 변경됨) 66 | -------------------------------------------------------------------------------- /docs/js/condition.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Condition 3 | --- 4 | 5 | # 조건문(Condition) 6 | 7 | 조건문은 주어진 조건을 만족할 때만 코드를 실행하게 하는 문법입니다. 조건에 따라서 다른 동작을 실행하고 싶을 때 조건문을 사용합니다. 특정 기능을 구현할 때는 여러 가지 케이스를 고려해서 코드를 작성해야 하므로 변수 다음으로 가장 많이 사용되는 문법입니다. 8 | 9 | 조건문에 대한 이해를 돕기 위해 간단한 예시를 살펴보겠습니다. 영화 티켓을 끊을 때 성인이면 10,000원을 내고 학생이면 5,000원을 내야 하는 결제 로직을 작성한다고 하면 다음과 같습니다. 10 | 11 | ``` 12 | 만약, 나이가 18세 이상이면 10,000원을 낸다. 13 | 그렇지 않고 나이가 17세 이하면 5,000원을 낸다. 14 | ``` 15 | 16 | 위 로직을 조건문으로 작성해 보면 다음과 같습니다. 17 | 18 | ```js 19 | var age = 24; 20 | if (age >= 18) { 21 | console.log('10,000원 지불'); 22 | } else { 23 | console.log('5,000원 지불'); 24 | } 25 | ``` 26 | 27 | ## if 조건문 28 | 29 | if 문은 주어진 조건식이 참이면 if 문 블록 안에 있는 코드를 실행합니다. 30 | 31 | ```js 32 | if (조건식) { 33 | // 조건식이 맞으면 이 블록 안의 코드가 실행됩니다. 34 | } 35 | ``` 36 | 37 | 위 문법을 이해하기 위해 간단한 예제를 보겠습니다. 38 | 39 | ```js 40 | var a = 10; 41 | if (a === 10) { 42 | console.log('10이 맞습니다'); 43 | } 44 | ``` 45 | 46 | 위 코드는 변수 `a`에 `10`이 할당되어 있으므로 if 문 안의 코드인 `console.log('10이 맞습니다')`가 실행됩니다. 이렇게 블록 안의 코드가 한 줄이든 여러 줄이든 블록 안의 코드는 모두 실행됩니다. 47 | 48 | ## if else 문 49 | 50 | 위에서 배운 if 문에서 조건식이 참이 아니라 거짓인 경우에 실행될 코드도 아래와 같이 작성할 수 있습니다. 51 | 52 | ```js 53 | if (조건식) { 54 | // 조건식이 맞으면 이 블록 안의 코드가 실행됩니다. 55 | } else { 56 | // 위 조건식이 틀리면 이 블록 안의 코드가 실행됩니다. 57 | } 58 | ``` 59 | 60 | 위 문법을 이용하여 앞 예제에 else 구문을 추가해 보겠습니다. 61 | 62 | ```js 63 | var a = 30; 64 | if (a === 10) { 65 | console.log('10이 맞습니다'); 66 | } else { 67 | console.log('a가 10이 아니면 이 코드가 실행됩니다'); 68 | } 69 | ``` 70 | 71 | 위 코드에서 변수 `a`의 값이 `10`이 아니기 때문에 `else` 문 블록 안의 코드가 실행됩니다. 최종적으로 `a가 10이 아니면 이 코드가 실행됩니다` 가 출력됩니다. 72 | 73 | ## else if 문 74 | 75 | else if 문은 조건식이 여러 개인 경우 사용할 수 있는 문법입니다. 기본 문법은 다음과 같습니다. 76 | 77 | ```js 78 | if (첫번째조건식) { 79 | // 첫번째조건식이 맞으면 이 블록 안의 코드가 실행됩니다. 80 | } else if (두번째조건식) { 81 | // 두번째조건식이 맞으면 이 블록 안의 코드가 실행됩니다. 82 | } 83 | ``` 84 | 85 | 위에서 조건문을 소개할 때 사용했던 조건을 다시 들고 와서 시나리오를 좀 더 추가해 보겠습니다. 86 | 87 | ``` 88 | 만약 나이가 65세 이상이면 돈을 내지 않는다. 89 | 만약 나이가 18세 ~ 65세 사이면 10,000원을 낸다. 90 | 그렇지 않고 나이가 17세 이하면 5,000원을 낸다. 91 | ``` 92 | 93 | 위 조건을 코드로 작성해 보면 다음과 같습니다. 94 | 95 | ```js 96 | var age = 24; 97 | if (age > 65) { 98 | console.log('무료'); 99 | } else if (18 <= age && age <= 65) { 100 | console.log('10,000원 지불'); 101 | } else { 102 | console.log('5,000원 지불'); 103 | } 104 | ``` 105 | 106 | 위 코드에서 `age` 값이 24이므로 18세 이상이고 65세 이하인 else if 구문에 해당됩니다. 따라서, `else if` 문 블록 안에 있는 코드가 실행되어 `10,000원 지불`이 출력됩니다. 107 | 108 | ## switch 문 109 | 110 | switch 문은 조건 식이 여러 개인 경우에 사용할 수 있는 조건문입니다. 바로 앞에서 배운 else if 구문과 역할이 같습니다. 기본 문법은 다음과 같습니다. 111 | 112 | ```js 113 | switch (변수) { 114 | case 값1: 115 | // 변수가 값1이면 실행할 로직 116 | break; 117 | case 값2: 118 | // 변수가 값2이면 실행할 로직 119 | break; 120 | default: 121 | // 변수가 위 어떤 케이스에도 해당하지 않는 경우 실행할 로직 122 | } 123 | ``` 124 | 125 | a의 값에 따라 출력값이 달라지는 간단한 예제 코드를 보겠습니다. 126 | 127 | ```js 128 | var num = 33; 129 | switch (num) { 130 | case 10: 131 | console.log('10입니다'); 132 | break; 133 | case 33: 134 | console.log('33입니다'); 135 | break; 136 | default: 137 | console.log('10과 33이 아닌 다른 숫자입니다.'); 138 | } 139 | ``` 140 | 141 | 위 코드가 실행되면 `33입니다`가 출력됩니다. 여기서 만약 `num` 값이 20이라면 `default` 블록에 정의한 `10과 33이 아닌 다른 숫자입니다.`가 출력됩니다. 142 | -------------------------------------------------------------------------------- /docs/js/function.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Function 3 | --- 4 | 5 | # Function 6 | 7 | 함수란 특정 기능을 수행하는 코드의 단위입니다. 좀 더 쉽게 설명하자면 코드 여러 줄이 모여 있는 코드 모음 정도가 되겠네요. 이 코드의 모음은 반드시 1개 이상의 목적이 있어야 합니다. 8 | 9 | 함수는 아래와 같이 생겼습니다. 10 | 11 | ```js 12 | function sumNumbers(a, b) { 13 | return a + b; 14 | } 15 | ``` 16 | 17 | 위의 `sumNumbers` 라는 함수는 두 개의 숫자를 넘겨 받아 합을 반환해주는 역할을 하고 있습니다. 사용하려면 아래와 같이 호출합니다. 18 | 19 | ```js 20 | sumNumbers(10, 20); // 30 21 | ``` 22 | 23 | ## 함수 표현식과 함수 선언문 24 | 25 | 다른 프로그래밍 언어와 다르게 자바스크립트는 함수를 선언하는 방법이 2가지가 있습니다. 26 | 27 | - 함수 표현식 28 | - 함수 선언문 29 | 30 | 각각의 형식을 코드로 살펴보겠습니다. 31 | 32 | ```js 33 | // 함수 표현식 34 | var sumNumbers = function(a, b) { 35 | return a + b; 36 | }; 37 | 38 | // 함수 선언문 39 | function sumNumbers(a, b) { 40 | return a + b; 41 | } 42 | ``` 43 | 44 | 일반적으로 많은 프로그래밍 가이드에서 함수 선언문을 더 추천하고 있지만, 개인 스타일에 따라서 얼마든지 선택하여 사용할 수 있습니다. 45 | 46 | ::: tip 47 | 함수 표현식과 같이 함수를 정의할 수 있는 이유는 자바스크립트에서는 함수도 변수나 인자로 취급할 수 있기 때문입니다. [일급 객체(first-class citizens)](https://developer.mozilla.org/en-US/docs/Glossary/First-class_Function)라는 특징에 대해서 알아보시면 좋을 것 같네요! 48 | ::: 49 | 50 | ## 함수형 사고와 함수형 프로그래밍 51 | 52 | 함수를 작성하실 때는 가급적 [단일 책임 원칙(Single Responsibility Principle)](https://en.wikipedia.org/wiki/Single_responsibility_principle)을 지켜주시면 좋습니다. 단일 책임 원칙이란 1개의 함수는 1개의 기능만 담당해야 한다는 프로그래밍 원칙입니다. 함수에 여러 가지 기능이 들어가면 들어갈수록 재사용하기가 어려워지며 이는 Vue.js 컴포넌트를 설계할 때도 사고 방식에 영향을 줄 수 있습니다. 53 | 54 | 단일 책임 원칙의 관점에서 잘 설계된 함수와 그렇지 않은 함수를 비교해보겠습니다. 55 | 56 | ```js 57 | // 잘 설계된 함수 58 | function sumNumbers(a, b) { 59 | return a + b; 60 | } 61 | ``` 62 | 63 | 위 함수는 함수 명에서도 알 수 있지만 두 수의 합을 구하는 간단한 함수입니다. 두 개의 숫자를 더하는 행위에만 관심을 가지고 있고, 덧셈 로직을 제외한 나머지 코드는 넣지 않았습니다. 64 | 65 | 아래는 같은 함수 명으로 다른 로직을 수행하는 함수입니다. 66 | 67 | ```js 68 | // 단일 책임 원칙에 벗어나는 함수 69 | function sumNumbers(a, b) { 70 | var num = 1000; 71 | var data = {}; 72 | 73 | $.get('domain.com/products/1').then(function(response) { 74 | data = response.data; 75 | }); 76 | 77 | var total = a + b + num; 78 | return total; 79 | } 80 | ``` 81 | 82 | 위 함수의 이름은 `sumNumbers`라는 함수의 이름을 갖고 있지만, 실제로 두 수를 더하는 로직 이외에도 데이터 요청이나 다른 숫자를 더하는 로직들이 뒤엉켜 있습니다. 위와 같은 코드는 단일 책임 원칙에 벗어나는 코드이며 재사용하기가 쉽지 않습니다. 83 | 84 | 좀 더 나아가서 앞의 함수를 단일 책임 원칙의 관점에서 리팩토링 해보면 아래와 같이 바뀔 수 있습니다. 85 | 86 | ```js {2,6,12} 87 | // 함수 리팩토링 88 | function sumNumbers(a, b) { 89 | return a + b; 90 | } 91 | 92 | function sumAll() { 93 | var num = 1000; 94 | var total = sumNumbers(0, 0) + num; 95 | return total; 96 | } 97 | 98 | function fetchData() { 99 | var data = {}; 100 | $.get('domain.com/products/1').then(function(response) { 101 | data = response.data; 102 | return data; 103 | }); 104 | } 105 | ``` 106 | 107 | 위와 같은 함수 설계에 관심을 갖다 보면 자연스럽게 함수형 프로그래밍에 대해 관심을 갖게 됩니다. 함수형 프로그래밍을 하기 위해서는 클로져(closure)라는 개념을 정확히 이해해야 하기 때문에 클로져 챕터에서 간략히 소개하겠습니다. 108 | -------------------------------------------------------------------------------- /docs/js/number.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Number 3 | --- 4 | 5 | # 숫자(Number) 6 | -------------------------------------------------------------------------------- /docs/js/object.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Object 3 | --- 4 | 5 | # Object 6 | 7 | 자바스크립트는 객체 기반 언어입니다. 객체는 키(key) - 값(value) 형태로 이루어져 있으며 아래와 같은 형태를 갖습니다. 8 | 9 | ```js 10 | var obj = { 11 | // 객체 내용 12 | }; 13 | ``` 14 | 15 | 위 코드는 obj라는 변수에 객체를 새로 할당한 코드입니다. 여기서 `{}`라는 기호가 객체를 의미하며 이를 객체 리터럴이라고 부릅니다. 일반적으로 객체를 생성할 때는 객체 리터럴을 사용하여 위와 같은 방식으로 선언합니다. 16 | 17 | ## 속성 추가 18 | 19 | 객체를 생성하고 나면 아래와 같은 방식으로 속성(property)를 추가할 수 있습니다. 20 | 21 | ```js 22 | // 객체 정의 23 | var obj = {}; 24 | 25 | // num 속성을 추가하고 숫자 10을 할당 26 | obj.num = 10; 27 | ``` 28 | 29 | 위와 같은 방법 이외에도 아래와 같이 속성을 추가할 수 있습니다. 30 | 31 | ```js 32 | // 객체 정의 33 | var obj = {}; 34 | 35 | // num 속성을 추가하고 숫자 20을 할당 36 | obj['num'] = 20; 37 | ``` 38 | 39 | ## 속성 값 변경 40 | 41 | 이미 정의한 속성을 변경하는 방법은 해당 속성을 다시 접근하여 값을 할당하는 것입니다. 42 | 43 | ```js 44 | // 객체 정의 45 | var obj = {}; 46 | 47 | // num 속성을 추가하고 숫자 10을 할당 48 | obj.num = 10; 49 | 50 | // num 속성의 값에 숫자 20을 다시 할당 51 | obj.num = 20; 52 | ``` 53 | -------------------------------------------------------------------------------- /docs/js/operator.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Operator 3 | --- 4 | 5 | # 연산자(Operator) 6 | 7 | 연산자는 프로그래밍 로직을 구현할 때 논리식이나 산술식을 표현하기 위해 사용하는 기호들을 의미합니다. 주로 코드에서 흔하게 마주치는 아래와 같은 기호들을 의미합니다. 8 | 9 | - 산술 연산자 : `+`, `-`, `*`, `/`, `%` 10 | - 논리 연산자 : `||`, `&&` 11 | - 조건 연산자 : `? :` 12 | - 관계 연산자 : `>`, `<`, `===` 13 | 14 | ::: tip 15 | 각 연산자의 의미에 대해서는 MDN 문서 또는 자바스크립트 기초 책을 참고하세요. 16 | ::: 17 | 18 | ## 연산자의 활용 1 - 변수 초기화 19 | 20 | 논리 연산자를 이용해 변수 초기화 하는 방법에 대해서 알아보겠습니다. 일반적으로 변수의 초기화는 다음과 같은 방법으로 많이 합니다. 21 | 22 | ```js {3-5} 23 | function fetchData(data) { 24 | var receivedData; 25 | if (data === undefined) { 26 | receivedData = localStorage.getItem('item'); 27 | } 28 | } 29 | ``` 30 | 31 | 함수의 인자로 넘어온 값을 if 문으로 확인한 뒤 추가 로직을 실행하는게 대부분의 초기화 문법입니다. 여기서 논리 연산자를 활용하면 아래와 같이 깔끔하게 코드를 구현할 수 있습니다. 32 | 33 | ```js {3} 34 | function fetchData(data) { 35 | var receivedData; 36 | receivedData = data || localStorage.getItem('item'); 37 | } 38 | ``` 39 | 40 | ## 연산자의 활용 2 - 조건문 대신 삼항 연산자 41 | 42 | 로직을 구현하다가 보면 if 문을 중첩해서 활용하는 경우가 많습니다. 아래와 같이 말이죠. 43 | 44 | ```js {3-7} 45 | if (data !== undefined) { 46 | num = 50; 47 | if (num > 10) { 48 | num = 100; 49 | } else { 50 | num = 0; 51 | } 52 | } 53 | ``` 54 | 55 | 이럴 때 if 문 대신 삼항 연산자를 활용하면 더 코드를 간결하게 짤 수 있습니다. 56 | 57 | ```js {3} 58 | if (data !== undefined) { 59 | num = 50; 60 | num = num > 10 ? 100 : 0; 61 | } 62 | ``` -------------------------------------------------------------------------------- /docs/js/scope.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Scope 3 | --- 4 | 5 | # 스코프(Scope) 6 | 7 | 스코프란 변수의 유효 범위를 의미합니다. 8 | 9 | ## 글로벌 스코프 10 | 11 | 다른 프로그래밍 언어와는 다르게 자바스크립트의 변수는 유효 범위가 전역으로 시작합니다. 예를 들어 아래와 같은 변수 선언은 자바스크립트로 접근할 수 있는 모든 영역에서 같은 값을 갖습니다. 12 | 13 | ```js 14 | var a = 10; 15 | ``` 16 | 17 | 만약 함수를 만들어 아래와 같이 접근하더라도 동일한 값을 출력하게 됩니다. 18 | 19 | ```js 20 | var a = 10; 21 | 22 | function getA() { 23 | console.log(a); 24 | } 25 | 26 | getA(); // 10 27 | ``` 28 | 29 | ## 로컬 스코프 30 | 31 | 기본적으로 변수의 유효 범위는 전역 범위를 갖는다고 하지만, 함수 안에서 새로 선언하는 경우 함수 단위의 지역 범위인 함수 스코프를 갖습니다. 아래 코드를 보겠습니다. 32 | 33 | ```js 34 | var a = 10; 35 | 36 | function getA() { 37 | var a = 20; 38 | console.log(a); 39 | } 40 | 41 | getA(); // 20 42 | console.log(a); // 10 43 | ``` 44 | 45 | 위 코드는 함수 바깥에서 변수 `a`를 선언하고 10을 대입한 뒤, `getA()`라는 함수를 선언하면서 함수 안에 변수 `a`를 새로 선언하고 20을 대입한 코드입니다. `getA()` 함수를 실행하면 함수 안의 변수인 `a`가 20의 값으로 콘솔에 출력됩니다. 함수의 실행이 끝나고 나서 `console.log(a);`로 다시 `a`의 값을 출력하면 10이 출력됩니다. 46 | 47 | 여기서 변수의 유효 범위는 함수 단위로 한정된다는 것을 알 수 있습니다. 48 | 49 | ## 스코프 체인 50 | 51 | 변수를 찾을 때 먼저 자신이 속한 스코프에서 찾고 없으면 상위 스코프에서 찾는 현상을 스코프 체인(Scope Chain)이라고 합니다. 52 | 53 | 간단한 예제로 앞의 코드를 다시 살펴보겠습니다. 54 | 55 | ```js 56 | // 글로벌 스코프 57 | var a = 10; 58 | 59 | function getA() { 60 | // 로컬 스코프 61 | console.log(a); 62 | } 63 | 64 | getA(); // 10 65 | ``` 66 | 67 | `getA()` 함수가 실행이 되면 먼저 지역 범위인 `getA()` 함수 안에서 변수 `a`를 찾고 `getA()` 함수에는 변수 `a`가 없기 때문에 상위 스코프인 전역 범위에서 변수 `a`를 다시 찾습니다. 68 | 69 | 다음 예제를 보겠습니다. 70 | 71 | ```js 72 | // 글로벌 스코프 73 | var a = 10; 74 | 75 | function outer() { 76 | // 외부 함수 스코프 77 | var b = 20; 78 | 79 | function inner() { 80 | // 로컬 함수 스코프 81 | var c = 30; 82 | console.log(a); 83 | console.log(b); 84 | console.log(c); 85 | } 86 | inner(); 87 | }; 88 | outer(); 89 | 90 | // 결과 91 | // 10 92 | // 20 93 | // 30 94 | ``` 95 | 96 | 위의 코드는 `inner()` 함수에서 `a, b, c` 변수를 참조할 때 스코프 체인에 의해서 `inner()` 로컬 함수 스코프, `outer()` 외부 함수 스코프, 글로벌 스코프의 순서로 변수를 찾습니다. 97 | 98 | ## 렉시컬 스코프 99 | 100 | 앞에서 자신의 스코프에서 변수를 찾고 없으면 상위 스코프에서 찾는 스코프 체인에 대해 알아보았습니다. 그렇다면 이 상위 스코프는 어떤 기준으로 정하게 되는 것일까요? 101 | 102 | 자바스크립트는 함수를 어디서 선언하였는지에 따라서 상위 스코프를 결정하는 렉시컬 스코프(Lexical Scope) 규칙을 따릅니다. 103 | 104 | ```js 105 | // 글로벌 스코프 106 | var a = 10; 107 | var b = 20; 108 | function getA() { 109 | var b = a; 110 | getB(); 111 | } 112 | 113 | function getB() { 114 | // 로컬 함수 스코프 115 | console.log(b); 116 | } 117 | 118 | getB(); // 20 119 | getA(); // 20 120 | 121 | ``` 122 | 123 | 위 코드에서 `getB()` 함수는 전역 범위에 선언되었기 때문에 호출된 위치와 상관없이 상위 스코프로 갖는 글로벌 스코프와 자기 자신인 로컬 함수 스코프를 최종 스코프를 갖게 되서 둘 다 20을 출력합니다. 124 | 125 | 이와 반대되는 개념인 다이나믹 스코프(Dynamic Scope) 규칙을 따르는 언어는 함수의 호출 위치에 따라 상위 스코프가 결정됩니다. 126 | 127 | ```sh 128 | #!/bin/sh 129 | 130 | A=10 131 | B=20 132 | 133 | getA(){ 134 | B=$A 135 | getB 136 | } 137 | 138 | getB(){ 139 | echo $B 140 | } 141 | 142 | getB # 20 143 | getA # 10 144 | ``` 145 | 146 | 다이나믹 스코프 규칙을 따르는 쉘 스크립트는 20, 10이 출력 됩니다. 147 | -------------------------------------------------------------------------------- /docs/js/string.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: String 3 | --- 4 | 5 | # 문자열(String) 6 | 7 | 문자열은 변수의 여러 타입 중 하나입니다. 일반적으로 스트링이라고도 부르며 아래와 같이 선언합니다. 8 | 9 | ```js 10 | var a = 'hello'; 11 | ``` 12 | 13 | 위 코드는 `a`라는 변수에 `hello`라는 문자열을 할당한 코드입니다. 문자열은 이와 같이 작은 따옴표(') 또는 큰 따옴표(")를 이용하여 정의할 수 있습니다. 14 | 15 | ## 숫자와의 구분 16 | 17 | 자바스크립트는 코드를 실행하는 시점에 변수의 타입을 결정하는 언어입니다. 이러한 특징이 초심자들에게는 편하지만 아래와 같이 타입을 헷갈리게 하는 경우가 생깁니다. 18 | 19 | ```js 20 | var a = 10; 21 | var b = '10'; 22 | console.log(a); // 10 23 | console.log(b); // 10 24 | ``` 25 | 26 | 위 코드에서 변수 `a`는 숫자고 변수 `b`는 문자열입니다. 콘솔 로그 코드를 이용하여 콘솔에 변수의 값을 출력해보면 육안으로는 구분하기가 어렵다는 사실을 알 수 있습니다. 27 | 28 | 여기서 `typeof`를 이용하여 변수의 타입을 확인할 수도 있겠지만 실무 관점에서는 아래와 같은 방법으로 구분할 수 있습니다. 29 | 30 | ```js 31 | console.log(a.length); // undefined 32 | console.log(b.length); // 2 33 | ``` 34 | 35 | 여기서 `length` 라는 예약어는 자바스크립트에서 변수의 타입에 따라 제공하는 기능입니다. length는 문자열, 배열의 길이를 숫자 형태로 확인할 수 있습니다. 따라서 `b`는 문자열이고 `a`는 숫자임을 추측할 수가 있습니다. 36 | 37 | 위와 같이 타입에 따라 기본적으로 제공되는 예약어 및 기능들을 자바스크립트 내장 함수(JavaScript Built-in API / JavaScript Native API)라고 합니다. 내장 함수에 대해서는 [prototype](/js/prototype.html)에서 자세히 설명하겠습니다. 38 | -------------------------------------------------------------------------------- /docs/js/this.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: this 3 | --- 4 | 5 | # this 6 | 7 | this는 함수의 실행 컨텍스트를 가리키는 예약어입니다. 여기서 실행 컨텍스트는 사전적인 정의로 '**함수가 실행되는 환경**'이며 좀 더 쉽게 접근하기 위해서는 '**함수가 실행될 때의 컨텍스트**'로 이해하시는 게 좋겠습니다. 8 | 9 | 다른 언어와 다르게 자바스크립트의 this는 상황에 따라 다른 값들을 가르킵니다. 이 때문에 자바스크립트가 조금 어렵게 느껴지는 부분도 있습니다. 10 | 11 | 여기서는 this가 가장 많이 활용되는 상황들에 대해서 알아보겠습니다. 12 | 13 | ## 첫 번째 this 14 | 15 | 아래의 코드를 브라우저 콘솔에서 실행하면 어떻게 될까요? 16 | 17 | ```js 18 | console.log(this); // window 19 | ``` 20 | 21 | this의 가장 기본적인 컨텍스트는 **글로벌(전역) 컨텍스트**입니다. 여기서 출력된 window는 자바스크립트의 최상위 객체를 가리킵니다. 22 | 23 | ## 두 번째 this 24 | 25 | 아래와 같은 객체가 있다고 가정하겠습니다. 26 | 27 | ```js 28 | var obj = { 29 | num: 10, 30 | printNum: function() { 31 | console.log(this.num); 32 | } 33 | }; 34 | ``` 35 | 36 | 여기서 `obj.printNum()`을 실행하면 어떻게 될까요? 37 | 38 | ```js 39 | obj.printNum(); // 10 40 | ``` 41 | 42 | **객체 속성 함수 안에서의 this는 기본적으로 해당 객체를 가리킵니다.** 43 | 44 | ## 세 번째 this 45 | 46 | 세 번째로 살펴볼 this는 먼저 [함수 선언문](#함수-선언문), [생성자 함수](#생성자-함수)를 알아야 합니다. 혹시 아직 개념이 낯선 분들은 링크를 클릭해서 간단하게 살펴보시고 계속 읽어나가시는 것을 추천드립니다. 47 | 48 | 자 그럼 일반 함수(함수 선언문)에서의 this는 어떤 것을 가리킬까요? 49 | 50 | ```js 51 | function showComment() { 52 | console.log(this); 53 | } 54 | ``` 55 | 56 | 위 함수를 아래와 같이 실행시키면 `window` 객체를 가리키고 있다는 것을 알 수 있습니다. 결론적으로 **일반 함수의 this는 전역 컨텍스트입니다.** 57 | 58 | ```js 59 | showComment(); // window 60 | ``` 61 | 62 | 그럼 이번엔 생성자 함수의 this를 확인해보겠습니다. 63 | 64 | ```js 65 | function Developer() { 66 | console.log(this); 67 | } 68 | var dev = new Developer(); 69 | ``` 70 | 71 | 위 코드는 실행하자마자 바로 아래와 같은 결과를 콘솔에 출력합니다. 72 | 73 | ```js 74 | Developer {} 75 | ``` 76 | 77 | 그 이유는 `new`로 인스턴스를 생성하는 순간 함수가 실행되기 때문입니다. 그리고 여기서 알 수 있는 사실은 **생성자 함수의 this는 함수의 내부를 가리킨다는 것**입니다. 78 | 79 | ## 네 번째 this 80 | 81 | 네 번째로 살펴볼 this는 실제로 웹 개발을 할 때 가장 많이 마주하게 되는 this입니다. 바로 데이터를 받아올 때 사용하는 HTTP 요청과 같은 비동기 처리 코드입니다. 82 | 83 | ```js 84 | function fetchData() { 85 | axios.get('domain.com/products').then(function() { 86 | console.log(this); 87 | }); 88 | } 89 | ``` 90 | 91 | 위 함수를 실행하면 어떤 결과가 나타날까요? 정답은 window입니다. 92 | 93 | ```js 94 | fetchData(); // window 95 | ``` 96 | 97 | 기본적으로 HTTP 요청과 같은 비동기 처리 코드는 전역 컨텍스트를 갖습니다. 정리해서 **비동기 처리 코드의 콜백 함수는 전역 컨텍스트를 가리킨다**고 보면 되겠습니다. 98 | 99 | ## 부록 100 | 101 | 위 본문을 이해하는데 도움이 되는 자료들입니다. 102 | 103 | ### 함수 선언문 104 | 105 | 함수 선언문은 아래와 같은 함수 정의 방식을 의미합니다. 106 | 107 | ```js 108 | // 함수 선언문 109 | function functionName() { 110 | // ... 111 | } 112 | ``` 113 | 114 | ### 생성자 함수 115 | 116 | 그리고 생성자 함수는 아래와 같이 함수를 이용해 새 인스턴스를 선언하는 함수를 의미합니다. 117 | 118 | ```js 119 | function Developer() { 120 | // ... 121 | } 122 | var dev = new Developer(); 123 | ``` 124 | 125 | ::: tip 126 | 자바스크립트는 프로토타입 기반 언어입니다. 클래스 기반 언어가 아니기 때문에 위와 같이 함수를 이용하여 인스턴스를 생성할 수 있습니다. 자바 개발자 분들은 클래스가 없다고 당황하지 마세요 :) 127 | ::: 128 | -------------------------------------------------------------------------------- /docs/js/variable.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Variable 3 | --- 4 | 5 | # 변수(Variable) 6 | 7 | ## 소개 8 | 9 | 변수는 프로그래밍 언어의 가장 기본적인 개념입니다. 변수는 변하는 값을 의미하고 특정 데이터를 담는 용기나 그릇과 같습니다. 변하는 값을 저장하는 공간을 변수라고 합니다. 프로그래밍을 할 때 로직의 대부분은 변수를 기반으로 작성하게 됩니다. 단순한 덧셈 등의 사칙 연산부터 시작하여 복잡한 로직의 계산까지 모두 변수가 관여합니다. 10 | 11 | 자바스크립트에서 변수는 아래와 같이 정의할 수 있습니다. 12 | 13 | ```js 14 | var a; 15 | ``` 16 | 17 | 위는 `a`라는 변수를 선언한 코드입니다. 변수를 선언하고 아무 값도 할당하지 않으면 기본적으로 `undefined` 라는 초기값을 가집니다. 18 | 19 | ## 변수에 값 할당하기 20 | 21 | 일반적으로 변수를 선언하고 나면 변수 안에 원하는 값을 정의할 수 있습니다. 22 | 23 | ```js 24 | var a; 25 | a = 10; 26 | ``` 27 | 28 | 위 코드는 `a`라는 변수를 정의하고 이 변수에 `10`이라는 숫자를 할당한 코드입니다. 다른 프로그래밍 언어와 달리 자바스크립트가 입문자에게 좋은 이유는 위와 같이 변수의 타입(종류)을 정의하지 않아도 코드를 실행할 때 자동으로 타입이 결정된다는 점입니다. 29 | 30 | 아래와 같이 유연하게 코드의 값을 바꿀 수 있습니다. 31 | 32 | ```js 33 | var a; 34 | a = 10; 35 | console.log(a); // 10 36 | 37 | a = 'hi'; 38 | console.log(a); // hi 39 | 40 | a = false; 41 | console.log(a); // false 42 | ``` 43 | 44 | ## 변수명 규칙 45 | 46 | 변수명은 영어와 한글 모두 사용할 수 있습니다. 숫자도 사용할 수는 있지만 숫자로 시작되어선 안됩니다. `$`, `_` 등의 특수문자를 사용할 수 있고 대소문자가 구분됩니다. 47 | 48 | ```js 49 | // 가능한 변수명 50 | var myName; 51 | var 내이름; 52 | var 내첫번째이름; 53 | var _a; 54 | var $won; 55 | ``` 56 | 57 | 변수명에 [예약어](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Lexical_grammar#reserved_keywords_as_of_ecmascript_2015)를 사용할 수 없습니다. 58 | 59 | ```js 60 | // 불가능한 변수명 61 | var 1이름; 62 | var continue; 63 | var function; 64 | ``` 65 | 66 | ## 변수의 타입 확인하기 - typeof 67 | 68 | 앞에서 본 것처럼 `a`라는 변수의 값은 숫자, 문자열, 진위 값 순서로 변경되었습니다. 여기서는 다행히 할당한 값을 쉽게 구분할 수 있었지만 실제로 코딩하다보면 아래와 같이 쉽게 타입을 추측하기가 어렵습니다. 69 | 70 | ```html 71 | 72 | ``` 73 | 74 | ```js 75 | var divElement = document.querySelector('input').value; 76 | console.log(divElement); 77 | ``` 78 | 79 | 이 때 `divElement` 변수의 타입을 확인할 수 있는 방법은 아래와 같습니다. 80 | 81 | ```js 82 | console.log(typeof divElement); 83 | ``` 84 | 85 | 이처럼 변수의 타입은 typeof 라는 예약어로 확인할 수 있습니다. 86 | 87 | ::: tip 88 | 예약어 : 언어에서 미리 지정해놓은 키워드, 단어 89 | ::: 90 | -------------------------------------------------------------------------------- /docs/legacy/chart.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Wrapping External Library II 3 | --- 4 | 5 | # 차트 라이브러리 통합 6 | 7 | 외부 라이브러리를 뷰에 통합하는 실습 2번째는 차트 라이브러리입니다. 차트 라이브러리는 기업의 백오피스(Back office)나 모니터링 시스템에서 흔하게 사용됩니다. 뷰 프레임워크 용으로도 차트 라이브러리들이 나오고 있지만 아직은 뷰와 통합된 라이브러리들이 많지가 않아 직접 통합해서 사용할 줄 알아야 합니다. 8 | 9 | ## 실습 예제 10 | 11 | 통합할 차트 라이브러리는 [Chart.js](https://www.chartjs.org/)입니다. 이미 뷰로 통합된 라이브러리가 오픈소스로 나와 있지만 직접 통합해보면서 감각을 익혀보겠습니다. 그리고 이번에는 뷰 플러그인으로 변환하여 사용하는 방법들을 알아보겠습니다. 12 | 13 | ## 실습 포인트 14 | 15 | 1. 컴포넌트 모듈화 16 | 2. 뷰 라이프사이클에 대한 이해 17 | 3. 컴포넌트 통신 방식에 대한 이해 18 | 4. 플러그인에 대한 이해 19 | 20 | ## 실습 코드 21 | 22 | - [연습 코드는 여기서](https://github.com/joshua1988/vue-camp/tree/vue6-class/2_todo/chart-with-plugin/exercise) 23 | - [답안 코드는 여기서](https://github.com/joshua1988/vue-camp/tree/vue6-class/2_todo/chart-with-plugin/answer) -------------------------------------------------------------------------------- /docs/legacy/datepicker.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Wrapping External Library I 3 | --- 4 | 5 | # 날짜 선택기 라이브러리 통합 6 | 7 | 실무의 레거시 프로젝트를 뷰로 바꾸는 경우 기존에 사용하던 라이브러리를 뷰로 래핑해야 하는 경우가 생깁니다. 일반적으로 기존 시스템에 적용된 라이브러리는 바닐라 자바스크립트 또는 jQuery 기반으로 되어 있는 경우가 많습니다. 따라서, 뷰 개발자는 이와 같은 라이브러리를 뷰의 동작 원리에 맞춰 통합할 줄 알아야 합니다. 8 | 9 | 라이브러리를 뷰로 래핑할 때 알아야 하는 뷰의 특징은 가상 돔(Virtual DOM) 기반으로 템플릿을 구현한다는 점입니다. 뷰 인스턴스가 화면에 부착되는 시점이 언제인지 잘 모르시는 분들은 [뷰 인스턴스 라이프사이클](../vue/life-cycle.html)을 다시 살펴보세요. 10 | 11 | ## 실습 예제 12 | 13 | 뷰로 통합할 라이브러리는 날짜 선택기(DatePicker) 라이브러리입니다. 날짜 선택기 라이브러리는 jQuery 플러그인으로도 있고 독립 라이브러리로도 많이 있습니다. 여기서는 [Pickaday](https://github.com/dbushell/Pikaday)를 기준으로 실습하겠습니다. 14 | 15 | ## 실습 포인트 16 | 17 | 1. 컴포넌트 모듈화 18 | 2. 뷰 라이프사이클에 대한 이해 19 | 3. 컴포넌트 통신 방식에 대한 이해 20 | 4. v-model 내부 동작 방식에 대한 이해 21 | 22 | ## 실습 코드 23 | 24 | - [연습 코드는 여기서](https://github.com/joshua1988/vue-camp/tree/vue6-class/2_todo/external-library/exercise) 25 | - [답안 코드는 여기서](https://github.com/joshua1988/vue-camp/tree/vue6-class/2_todo/external-library/answer) 26 | -------------------------------------------------------------------------------- /docs/legacy/form.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Form 3 | --- 4 | 5 | # Form 6 | 7 | 앞에서 연습했던 제이쿼리의 사고 방식에서 벗어나기 위해 실습 한 개를 더 해보겠습니다. 제이쿼리로 구현된 사용자 입력폼이 아래와 같이 있을 때 어떻게 뷰로 바꿀 수 있을까요? 8 | 9 | ```html 10 |
11 |
12 | 15 | 17 |
18 |
19 | 22 | 24 |

Please choose a password.

25 |
26 |
27 | 31 | 32 | Forgot Password? 33 | 34 |
35 |
36 | 37 | 67 | ``` 68 | 69 | [연습 코드는 여기서](https://github.com/joshua1988/vue-camp/tree/vue6-class/1_essentials/form/exercise)
70 | [답안 코드는 여기서](https://github.com/joshua1988/vue-camp/tree/vue6-class/1_essentials/form/answer) -------------------------------------------------------------------------------- /docs/legacy/jquery-to-vue.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: jQuery to Vue 3 | --- 4 | 5 | # 제이쿼리에서 뷰 사고 방식으로 전환하기 6 | 7 | ## 뷰 개발자가 마주하는 현실 8 | 9 | 제이쿼리(jQuery)는 현재까지도 많은 기업들이 사용하고 있는 자바스크립트 라이브러리입니다. 아마도 뷰를 배우고 나면 가장 먼저 부딪히는 일들이 제이쿼리로 제작된 애플리케이션의 기능을 수정해야 하는 일 일겁니다. 10 | 11 | ::: tip 12 | jQuery는 DOM을 쉽게 조작하기 위한 라이브러리입니다. 13 | ::: 14 | 15 | ## 제이쿼리와 뷰의 차이점 16 | 17 | 제이쿼리와 뷰의 가장 큰 차이점은 화면 요소를 직접 접근하느냐 그렇지 않느냐입니다. 더 쉽게 이해하기 위해 두 라이브러리의 DOM 접근 방법을 살펴보겠습니다. HTML 코드는 아래와 같이 간단한 버튼 태그를 사용하겠습니다. 18 | 19 | ```html 20 | 21 | ``` 22 | 23 | ### 제이쿼리의 버튼 태그 접근 24 | 25 | 제이쿼리는 특정 태그를 접근하기 일반적으로 태그에 id 속성을 부여하고 제이쿼리 선택자($)를 활용합니다. 26 | 27 | ```html 28 | 29 | ``` 30 | 31 | ```js 32 | $('#btn'); 33 | ``` 34 | 35 | 위 코드는 btn 아이디를 가지는 DOM을 접근하는 코드입니다. 36 | 37 | ### 뷰의 버튼 태그 접근 38 | 39 | 이번엔 뷰입니다. 뷰로 특정 태그로 접근하려면 ref 속성을 활용합니다. 위의 버튼 태그에 ref 속성을 부여하고 접근해보겠습니다. 40 | 41 | ```html 42 | 43 | ``` 44 | 45 | ```js 46 | this.$refs.btn 47 | ``` 48 | 49 | 이처럼 바로 접근하고 싶은 태그에 ref 속성을 지정하여 사용합니다. 50 | 51 | ## 제이쿼리와 뷰를 같이 쓸 때 주의할 점 52 | 53 | 보통 뷰를 배우시고 나면 기존의 제이쿼리 기반 시스템을 개편하거나 새로 서비스를 만드는 경우가 많습니다. 여기서 전자의 비율이 상당히 높습니다. 그러면 제이쿼리 기반의 코드, 플러그인 라이브러리 사용시에 주의할 점을 알아보겠습니다. 주의할 점은 바로 뷰의 인스턴스 라이프사이클입니다. 54 | 55 | 뷰의 라이프사이클이란 뷰의 인스턴스가 생성되고 소멸되기까지의 과정입니다. 그리고 라이프사이클 훅이라는 게 있는데 주로 사용되는 건 아래와 같습니다. 56 | 57 | - created 58 | - beforeMount 59 | - mounted 60 | 61 | 여기서 제이쿼리의 선택자로 HTML 태그를 접근할 수 있는 시점은 mounted 단계입니다. 코드로 예를 들어보겠습니다. 62 | 63 | ```html 64 | 69 | 70 | 81 | ``` 82 | 83 | 위 코드는 뷰의 싱글 파일 컴포넌트(vue 파일 확장자) 코드 구조에서 제이쿼리를 함께 사용하는 모습입니다. `