본문 바로가기
Tech/Vue.js

[Vue.js] 컴포넌트 기초

by 소라소라잉 2020. 7. 29.

컴포넌트란?

 

컴포넌트는 하나의 블록을 의미한다. 컴포넌트를 활용하여 화면을 만들면 보다 빠르게 구조화하여 일괄적인 패턴으로 개발할 수 있다. 화면의 영역을 컴포넌트로 분리함으로써 재사용 편리한 코드가 구조가 되는것이다.

쇼핑몰의 화면을 예를 들어보면, 화면의 header, footer, menu 등을 컴포넌트단위로 분리하여 어느 화면에서나 재사용 할 수 있고, 더 세부적으로 장바구니 버튼 같은 것들을 분리하여 재사용 할 수도 있다.  

 

 

전역, 지역 컴포넌트

 

전역 컴포넌트 등록은 Vue.component(tagName, options)를 사용한다. 

컴포넌트를 components 인스턴스 옵션으로 등록하여 다른 인스턴스/컴포넌트의 범위에서만 사용할 수있는 지역적인 컴포넌트를 만들 수도 있다. 

 

app.html 

<div id="example1">
    <p>Example1 : 전역 컴포넌트</p>
    <my-template></my-template>
</div>

<div id="example2">
    <p>Example2 : 지역 컴포넌트</p>
    <localcomp></localcomp>
</div>

<div id="example3">
    <p>Example3 : 전역,지역 컴포넌트</p>
    <my-template></my-template>
    <localcomp></localcomp>
</div>


app.js

Vue.component('my-template', {
        template: '<b>전역 컴포넌트입니다!</b>'
    })

    let example1 = new Vue({
        el: '#example1'
    })


    let LocalComponent = {
        template : `<b>지역 컴포넌트입니다!</b>`
    }

    let example2 = new Vue({
        el: '#example2'
        , components : {
            'localcomp' : LocalComponent
        }
    })

    let example3 = new Vue({
        el : '#example3'
    })


위의 예제에서 전역 컴포넌트로 등록한 my-template은 example1, example3 div에 나타날 수 있으나, example2 인스턴스에만 components로서 지역적으로 등록된 LocalComponent는 example2 div에서만 나타난다. 

 

결과화면

컴포넌트 작성시 주의할 점 - data는 반드시 함수여야 한다.

 

Vue 생성자에 사용하는 대부분의 옵션은 컴포넌트에서 사용할 수 있다. 다만, data는 필히 함수여야 한다.

 

app.html

<div id="example1">
<my-component></my-component>
<my-component></my-component>
<my-component></my-component>
</div>

 

app.js

    let data = {counter : 0}

    Vue.component('my-component', {
        template : `<button @click="counter += 1">{{counter}}</button>`
        , data: function () {
            // 이 경우 각 컴포넌트가 동일한 data를 공유하고 있어 
            // 버튼 클릭시 모든 버튼(data)이 counter된다.
            // return data;
            
            // 따라서 각각 새로운 counter 객체를 반환해야 한다. 
            return {counter : 0};
        }
    })

     new Vue({
        el : '#example1'
    })

 

 

props로 데이터 전달하기

 

하위컴포넌트의 템플릿에서 상위 컴포넌트의 데이터를 직접 참조할 수 없다. 데이터는 props 옵션을 통해서 하위컴포넌트로 전달되어질 수 있다. (상위->하위)

prop은 상위 컴포넌트의 정보를 전달하기위한 사용자 지정 특성이다. 하위 컴포넌트는 props 옵션을 사용하여 수신 할 것으로 기대되는 props를 명시적으로 선언해야한다. 

 

app.html

    <div id="example1">
        <h2>example1</h2>
        <p>I'm parent!</p>
        <child message="(상->하) props를 통한 데이터 전달"></child>
    </div>

 

app.js

        /* Ex1. child 컴포넌트의 prop활용 */
        new Vue({
            el: "#example1"
            , components: {
                child: {
                    props: ['message']
                    , template: '<span>{{ message }}</span>'
                }
            }
        })

 

'child'라는 이름의 template을 선언하고, <child>를 사용하는 쪽(상위 컴포넌트)에서 message를 전달한 예제이다. 

 

 

props의 이름 명시법(camelCase와 kebab-case) 

 

HTML속성은 대소문자를 구분하지 않으므로, template에서 사용한 cacelCase의 props이름을 kebab-case로 명시해야 한다. 

 

 

app.html

    <div id="example2">
        <h2>example2</h2>
        <camel my-message="camelCase vs kebab-case"></camel>
    </div>

 

 

app.js

        /* Ex2. script에서의 camelCase, html에서의 kebab-case */
        new Vue({
            el: "#example2"
            , components: {
                camel: {
                    props: ['myMessage']
                    , template: '<b>{{ myMessage }}</b>'
                }
            }
        })

 

동적 props

 

v-bind를 이용하여 부모의 데이터에 props를 동적으로 바인딩 할 수 있다.

데이터가 상위에서 업데이트 될 때마다 하위 컴포넌트로 전달된다. 

 

app.html

    <div id="example3">
        <h2>example3</h2>
        <input v-model="parentMsg">
        <mirror :message="parentMsg"></mirror>
    </div>

 

app.js

        /* Ex3. prop 동적 바인딩 */
        let model = {
            parentMsg: ''
        }

        new Vue({
            el: "#example3"
            , data: model
            , components: {
                mirror: {
                    props: ['message']
                    , template: '<b>{{ message }}</b>'
                }
            }
        })

 

결과화면

input 태그에 값이 입력되면 v-model의 양방향 바인딩 특성으로 해당 모델에 바인딩 되어있는 객체들의 데이터가 같이 변경된다.

mirror 컴포넌트의 message prop은 v-bind(:)로 parentMsg에 바인딩 되어있어 상위 컴포넌트의 데이터를 즉각 화면에 표시한다.  

 

 

객체의 모든 속성을 props로 전달하기

 

객체의 모든 속성을 props로 전달하려면, 인자없이 v-bind를 쓸 수 있다. (v-bind:prop-name 대신 v-bind)

 

app.html

    <!-- 객체의 모든 속성을 props로 전달하기 -->
    <div id="example4">
        <h2>example4</h2>
        <todo-item v-bind="todo"></todo-item>
    </div>

 

app.js

        /* Ex4. 객체의 모든 속성을 props로 전달하기 */
        let todo = {
            text: 'study hard'
            , isComplete : 'not yet :('
        }

        new Vue({
            el: "#example4"
            , data : {
                todo: todo
            }
            , components: {
                'todo-item': {
                    props: ['text', 'isComplete']
                    , template: '<b>{{text}} , {{isComplete}}</b>'
                }
            }
        })

 

 

댓글