목차

  1.  컴포넌트가 무엇인가요? 
  2.  컴포넌트 사용법
  3.  컴포넌트 뼈대 만들기
  4.  컴포넌트 내용 만들기
  5.  자식 컴포넌트 만들기
  6.  부모 자식간 이벤트 연결
  7.  부모의 데이터가 변경될 때 1
  8.  부모의 데이터가 변경될 때 2
  9.  끝으로...

1. 컴포넌트가 무엇인가요?

컴포넌트는 Vue의 가장 강력한 기능 중 하나입니다. 기본 HTML 엘리먼트를 확장하여 재사용 가능한 코드를 캡슐화하는 데 도움이 됩니다. 상위 수준에서 컴포넌트는 Vue의 컴파일러에 의해 동작이 추가된 사용자 지정 엘리먼트입니다. 경우에 따라 특별한 is 속성으로 확장 된 원시 HTML 엘리먼트로 나타날 수도 있습니다.



Vue.component('todo-list', {
  template: '<div>Todo List</div>'
});
  
new Vue({
  el: '#root',
  template: '<todo-list></todo-list>'
});

2. 컴포넌트 사용법

3. 컴포넌트 뼈대 만들기

<script type="application/javascript">
  Vue.component('todo-content', {
    template: `
    <div style="width: 720px; background: #dddddd; margin: 0 auto;">
      <h1>Todo List</h1>
      <slot></slot>
    </div>`
  });
  new Vue({
    el: '#root',
    template: `<todo-content></todo-content>`,
  });
</script>

4. 컴포넌트 내용 만들기

<script type="application/javascript">
  Vue.component('todo-content', {
    template: `
      <div class="todo-content">
         <h1>Todo List</h1>
         <slot></slot>
      </div>`
  });

  Vue.component('todo-list', {
    template: `
      <ul>
        <li>예시값</li>
      </ul>`
  });

  new Vue({
    el: '#root',
    template: `
      <todo-content>
        <todo-list></todo-list>
      </todo-content>`,
  });
</script>

5. 자식 컴포넌트 만들기

Vue.component('todo-content', {
  template: `
    <div class="todo-content">
      <h1>Todo List</h1>
      <slot></slot>
    </div>`
});

Vue.component('todo-list', {
  data() {
    return {
      items: ['A', 'B', 'C']
    }
  },
  template: `
    <ul>
      <todo-item 
        v-for="item in items" 
        :name="item"
      ></todo-item>
    </ul>`
});
Vue.component('todo-item', {
  props: ['name'],
  template: `<li>{{name}}</li>`
});

new Vue({
  el: '#root',
  template: `
    <todo-content>
      <todo-list></todo-list>
    </todo-content>`,
});

6. 부모 자식간 이벤트 연결 - 완료 버튼 

Vue.component('todo-list', {
  data () {
    return {
      items: ['A', 'B', 'C']
    }
  },
  methods: {
    completed (item) {
      const items = this.items;
      const i = items.indexOf(item);
      items.splice(i, 1);
    }
  },
  template: `
      <ul>
        <todo-item
          v-for="item in items"
          :key="item"
          :name="item"
          v-on:completed="completed"></todo-item>
      </ul>`
});
Vue.component('todo-item', {
  props: ['name'],
  methods: {
    complete () {
      this.$emit('completed', this.name);
    }
  },
  template: `
    <li>
      {{name}} 
      <button class="btn" @click="complete">완료</button>
    </li>`
});

7. 부모의 데이터가 변경 될 때 1 - 할일 추가

Vue.component('todo-list', {
  data() {
    return {
      inputItem: '',
      items: ['A', 'B', 'C']
    }
  },
  methods: {
    completed(item) {
      const items = this.items;
      const i = items.indexOf(item);
      items.splice(i, 1);
    },
    appendTodoItem() {
      this.items.push(this.inputItem);
      this.inputItem = '';
    }
  },
  template: `
      <div>
        <input class="input-text" type="text" v-model="inputItem"/>
        <button class="btn" @click="appendTodoItem">추가</button>
        <ul>
          <todo-item
            v-for="item in items"
            :key="item"
            :name="item"
            v-on:completed="completed"></todo-item>
        </ul>
      </div>`
});

8. 부모의 데이터가 변경 될 때 2 - 완료상태

Vue.component('todo-list', {
  data() {
    return {
      inputItem: '',
      items: [
        {job: 'A', isComplete: false},
        {job: 'B', isComplete: false},
        {job: 'C', isComplete: false}
      ]
    }
  },
  methods: {
    completedItem(job, isComplete) {
      const item = this.items.find(v => v.job === job);
      item.isComplete = isComplete;
    },
    deleteItem(job) {
      this.items = this.items.filter(v => job !== v.job);
    },
    appendTodoItem() {
      if (!this.inputItem) {
        window.alert('할일을 입력해주세요.');
        return false;
      }

      this.items.push({job: this.inputItem, isComplete: false});
      this.inputItem = '';
    }
  },
  template: `
      <div>
        <input class="input-text" type="text" v-model="inputItem"/>
        <button class="btn" @click="appendTodoItem">추가</button>
        <ul>
          <todo-item
            v-for="item in items"
            :key="item.job"
            :job="item.job"
            :isComplete="item.isComplete"
            v-on:completedItem="completedItem"
            v-on:deleteItem="deleteItem"></todo-item>
        </ul>
      </div>`
});
  • data: items의 데이터 구조 변경
  • 할일 완료 기능 변경
  • 할일 삭제 기능 추가
Vue.component('todo-item', {
  props: ['job', 'isComplete'],
  data() {
    return {
      _isComplete: false
    }
  },
  mounted() {
    this._isComplete = this.isComplete;
  },
  computed: {
    printJob() {
      return this.isComplete ?
        `<span class="completed">${this.job}</span>`:
        `${this.job}`
    }
  },
  methods: {
    completeJob() {
      this._isComplete = !this._isComplete;
      this.$emit('completedItem', this.job, this._isComplete);
    },
    deleteJob() {
      this.$emit('deleteItem', this.job);
    }
  },
  template: `
      <li>
        <span v-html="printJob"></span>
        <button v-if="isComplete" class="btn" @click="deleteJob">삭제</button>
        <button v-else class="btn" @click="completeJob">완료</button>
      </li>`
});
  • 작업전 완료 상태에 따른 렌더링
  • 할일 완료 기능 변경
  • 할일 삭제 기능 추가

끝으로...

  • 컴포넌트 기반 개발의 이해가 없다면 vue의 장점을 살리지 못할 수 있음
  • html의 복붙이 아닌 레고처럼 조립하여 페이지를 개발
  • 컴포넌트는 일단 크게 만들고 분리

fin