연산 로직이 필요할 경우 계산형 속성(Computed Property)를 사용해하여 필요한 함수를 등록할 수 있습니다.
함수 안에서 this는 Vue 객체 자신을 참조합니다.
num 값이 문자열로 다루어지기 때문에 Number(), parseInt() 함수를 사용해서 명시적으로 숫자로 변환해주어야 합니다.
1 2 3 4 5 6 7
computed : { sum : function() { var n = Number(this.num); if (Number.isNaN(n) || n < 1) return0; return ((1+n) * n) / 2; } }
Vue.js도 리액트 처럼 렌더링 속도 향상을 위해 가상DOM을 사용합니다. 가상 DOM에 대한 간단한 영상
Vue 인스턴스
el, data, computed
Vue 인스턴스에는 el, data, computed 옵션이 있습니다. 먼저 data 옵션에 주어진 모든 속성들은 Vue 인스턴스 내부에서 직접 이용되지 않고 Vue 인스턴스와 Data 옵션에 주어진 객체 사이에 프록시를 두어 처리합니다. 그래서 값에 접근할 때 vm.name으로 가능합니다. 직접 data에 접근하려면 vm.$data.name 방법이 있습니다.
1 2 3 4 5 6 7
var model = { name : "Ryan" } var vm = new Vue({ el : '#test', data : model })
el 옵션은 Vue 인스턴스에 연결할 HTML DOM요소를 지정하며 여러개 요소에 지정할 수 없습니다. Computed 옵션에 지정한 것은 함수였지만 Vue 인스턴스는 프록시 처리하여 마치 속성처럼 취급합니다.
메서드
Vue 인스턴스에서 사용할 메서드를 등록하는 옵션입니다. 직접호출, 디렉티브 포현식, 콧수염 표현식에서도 사용할 수 있습니다. 계산형 속성과 차이가 있다면 결과값의 캐싱 여부입니다. 메서드는 캐싱없이 매번 실행합니다.
1 2 3 4 5 6 7 8 9 10
<span>{{sum()}}</span> . . methods : { sum : function() { var n = Number(this.num); if (Number.isNaN(n) || n < 1) return 0; return ((1+n)*n)/2; } }
// HTML <div id="example"> <my-component></my-component> </div> . . // JS // 등록 Vue.component('my-component', { template: '<div>사용자 정의 컴포넌트 입니다!</div>' })
// 루트 인스턴스 생성 new Vue({ el: '#example' }) . . // 랜더링 결과 <div id="example"> <div>사용자 정의 컴포넌트 입니다!</div> </div>
단일 컴포넌트와 전역 컴포넌트의 차이점
<template> 에는 id 특서을 부여하지 않음
<script> 영역에서는 Vue 컴포넌트의 template을 지정하지 않음
Vue.component()로 이름과 template 속서을 지정하지 않음
단일 컴포넌트는 name 속성을 지정해 반드시 객체를 export 해야함
컴포넌트에서 사용할 스타일은 <style> 내부에 작성
전역 수준 컴포넌트의 문제점
빌드 단계가 없으므로 최신 자바스크립트 문법을 사용할 수 없습니다.
CSS 스타일을 빌드하고 모듈화할 수 있는 기능을 제공하지 않습니다.
컴포넌트 템플릿 작성시 HTML 파일안에 여러개의 <template /> 태그가 작성되어야 하기 때문에 식별이 어렵습니다.
Vue-CLI가 제공하는 프로젝트 템플릿 중 webpack-simple에 포함되어 있는 vue-loader라는 구성 요소가 단일 파일 컴포넌트를 지원합니다. 확장자가 .vue인 파일에 <template />, <script />, <style /> 을 작성하면 vue-loader는 이 파일을 파싱하고 다른 로더들을 활용해 하나의 모듈로 조합합니다. 특히, css-loader를 이용해 CSS 스타일을 전처리할 수 있으며, 스타일 정보를 모듈화할 수도 있습니다.
App.vue 파일을 열어보면 <template />, <script />, <style /> 3개의 기본 영역을 확인할 수 있습니다. App.vue 컴포넌트를 화면에 담기 위해 main.js를 사용합니다.
Child1.vue, Child2.vue에는 모두 main 클래스의 스타일이 적용되어 있습니다. 이럴경우, 두 스타일이 충돌되면서 마지막에 선언된 스타일이 적용됩니다. 이때, 스타일 태그에 scoped를 추가하면 이를 해결할 수 있습니다. 범위 CSS를 적용하면 data-v-xxxxx 형태의 속성이 부여됩니다.
특성 선택자(attribute selector)를 사용하기 때문에 브라우저에서 스타일 적용 속도가 느립니다. 그렇기 대문에 속도가 빠른 ID, 클래스, 태그명 선택자로 요소를 선택해 스타일을 적용해야 합니다.
부모 컴포넌트에 적용된 범위CSS는 하위 컴포넌트에도 반영이 됩니다.
2.CSS모듈
CSS모듈은 CSS를 객체처럼 다루는 것을 의미합니다. 설정하는 방법은 간단합니다. 스타일 태그에 module을 추가하면 CSS 모듈 모드가 작동되면서 그 결과로 생성된 클래스 식별 객체는 $style이름으로 컴포넌트의 계산형 속성으로 추가됩니다. 이 스타일은 Vue 인스턴스 내에서 $style 이라는 계산형 속성을 통해서 이용할 수 있습니다.
슬롯을 이용해 부모 컴포넌트에서 자식 컴포넌트로 HTML 마크업을 전달 할 수 있습니다. 슬롯을 사용하기 위해서 자식 컴포넌트에서는 <slot></slot> 태그를 작성하고 부모 컴포넌트에서는 콘텐츠 영역에서 자식 컴포넌트의 <slot></slot> 영역에 나타낼 HTML 마크업을 작성하면 됩니다.
1 2 3 4 5 6 7 8
// ChildComponent.vue <template> <div> <p>I'm the child component!</p> <!-- Content from the parent gets rendered here. --> <slot></slot> </div> </template>
// ParentComponent.vue <template> <div> <child-component> <p>I'm injected content from the parent!</p> <p>I can still bind to data in the parent's scope, like this! {{myVariable}}</p> </child-component> </div> </template>
data() { return { myVariable: `I'm just a lonely old variable.` } } } </script>
자식 컴포넌트에 <slot></slot>이 없을경우 부모로부터 전달되는 콘텐츠는 없어집니다. 반대로, 부모에서 어떠한 콘텐츠도 전달하지 않을경우, <slot></slot>에 엘리먼트를 추가하면 기본적으로 랜더링 됩니다.
1 2 3
<slot> <p>Hello from the child!</p> </slot>
명명된 슬롯
여러 개의 슬롯을 작성할 수 있습니다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
// BurgerComponent.vue <template> <div class="burger-component"> <!-- Elements injected with the `slot="top-bun"` attribute will end up in here. --> <slot name="top-bun"> </slot> <!-- A slot tag without a name is a catch-all, it will contain any content that doesn't have a `slot=""` attribute. --> <slot> </slot> <!-- Elements injected with the `slot="top-bun"` attribute will end up in here. --> <slot name="bottom-bun"> </slot> </div> </template>
// SecretRecipeBurger.vue <template> <!-- TOP SECRET, FOR EMPLOYEE EYES ONLY --> <burger-component> <burger-bun slot="top-bun"> <sesame-seeds></sesame-seeds> <mayonaise></mayonaise> </burger-bun> <burger-bun slot="bottom-bun" :toasted="true"> <secret-sauce></secret-sauce> <!-- I bought it from some hooded guy off the street. --> </burger-bun> <!-- Everything else gets injected into the middle slot (as it's not named.) --> <pickles></pickles> <lettuce></lettuce> <bacon></bacon> <beef-patty></beef-patty> <cheese-slice></cheese-slice> </burger-component> </template>