본문 바로가기

Vue.js

[Vue.js] 뷰 컴포넌트

컴포넌트란


조합하여 화면을 구성할 수 있는 블록(화면의 특정 영역)을 의미

컴포넌트를 활용하면 화면을 빠르게 구조화하여 일괄적인 패턴으로 개발할 수 있다

  • 재사용성
  • 직관적 이해

뷰에서는 웹 화면을 구성할 때 흔히 사용하는 네비게이션 바, 테이블, 리스트, 인풋 박스 등과 같은 화면 구성 요소들을 잘게 쪼개어 컴포넌트로 관리

 

 

 

 

 

 

 

컴포넌트 등록하기


📌 전역(Global) 컴포넌트 등록

 

여러 인스턴스에 공통으로 사용할 수 있다

뷰로 접근 가능한 모든 범위에서 사용 가능

 

뷰 라이브러리를 로딩하고 나면 접근 가능한 Vue  변수를 이용하여 등록한다 

전역 컴포넌트를 모든 인스턴스에 등록하려면 Vue생성자에서 .component()를 호출하여 수행하면 된다 

 

Vue.component('컴포넌트 이름', {
	
		//컴포넌트 내용    
    
});

 

  • 컴포넌트 이름
    • template 속성에서 사용할 HTML 사용자 정의 태그(custome tag) 이름을 의미
  • 컴포넌트 내용 
    • 컴포넌트 태그가 실제 화면의 HTML 요소로 변환될 때 표시될 속성들을 작성
    • template, data, methods 등 인스턴스 옵션 속성을 정의할 수 있다

 

<html>
    <head>
    	<title> Vue Compoenet Registration </title>
    </head>
    <body>
    	<div id="app">
            <button>컴포넌트 등록</button>
            <my-component></my-component> // 전역 컴포넌트 표시
        </div>
        
           <script src="https://cdn.jsdelivr.net/npm/vue@2.6.0"></script>
        <script>
        	// 전역 컴포넌트 등록
        	Vue.component('my-component', {
            	    template: '<div> 전역 컴포넌트 등록</div>'
            });
            
            new Vue({
            	el: '#app'
            });
        </script>
    </body>
</html>

 

✏️ 전역 컴포넌트가 화면에 나타나기까지의 처리 과정

뷰 라이브러리 파일 로딩 ->
뷰 생성자로 컴포넌트 등록 Vue.component() ->
인스턴스 객체 생성 (옵션 속성 포함) ->
특정 화면 요소에 인스턴스 부착 ->
인스턴스 내용 변환 (등록된 컴포넌트 내용도 변환)  <my-component> 가 <div> 로 변환됨 ->
변환된 화면 요소를 사용자가 최종 확인

 

 

 

 

 

📌 지역(Local) 컴포넌트 등록

특정 인스턴스에서만 유효한 범위를 갖는다

 

전역 컴포넌트 등록과는 다르게 인스턴스에 components 속성을 추가하고 등록할 컴포넌트 이름과 내용을 정의하면 된다 

new Vue({
   components: {
   	   '컴포넌트 이름': 컴포넌트 내용
   }
});

 

 

<html>
    <head>
    	<title> Vue Compoenet Registration </title>
    </head>
    <body>
    	<div id="app">
            <button>컴포넌트 등록</button>
            <my-local-component></my-local-component> // 지역 컴포넌트 표시
        </div>
        
           <script src="https://cdn.jsdelivr.net/npm/vue@2.6.0"></script>
        <script>
        
        	var cmp = {
            	// 컴포넌트 내용
                template: '<div> 지역 컴포넌트 등록 </div>'
            }
        	
            new Vue({
            	el: '#app'
                components: {
                	'my-local-component': cmp
                }
            });
        </script>
    </body>
</html>

 

 

 

 

 

 

📌 지역 컴포넌트와 전역 컴포넌트의 차이 

둘의 차이를 이해하기 위해서 인스턴스의 유효 범위를 이해해야 한다

💡 인스턴스 유효 범위
HTML 의 특정 범위 안에서만 인스턴스의 유효한 것 

 

 

<html>
    <head>
    	<title> Vue Compoenet  </title>
    </head>
    <body>
    	<div id="app">
        	<h3>첫 번째 인스턴스 영역</h3>
            <my-global-component></my-global-component> 
            <my-local-component></my-local-component> 
        </div>
        <hr>
        <div id="app2">
        	<h3>두 번째 인스턴스 영역</h3>
            <my-global-component></my-global-component> 
            <my-local-component></my-local-component> 
        </div>
        
           <script src="https://cdn.jsdelivr.net/npm/vue@2.6.0"></script>

        <script>
        
        	// 전역 컴포넌트 등록
        	Vue.component('my-global-component', {
            	template: '<div> 전역 컴포넌트 </div>'
            });
            
     
        	// 지역 컴포넌트 등록
        	var cmp = {
            	// 컴포넌트 내용
                template: '<div> 지역 컴포넌트 등록 </div>'
            }
        	
            new Vue({
            	el: '#app',
                components: {
                	'my-local-component': cmp
                }
            });
            
            // 두 번째 인스턴스 
             new Vue({
            	el: '#app2'  
            });
        </script>
    </body>
</html>

 

첫 번째 인스턴스 영역에는 전역, 지역 컴포넌트가 모두 정상적으로 나타남
구분선( <hr> ) 밑의 두번째 인스턴스 영역에는 전역 컴포넌트만 나타나고, 지역 컴포넌트가 나타나지 않음

유효범위가 다르기 때문!
전역 컴포넌트는 인스턴스를 새로 생성할 대마다 인스턴스에 components 속성으로 등록할 필요없이 한 번 등록하면 어느 인스턴스에서든지 사용할 수 있다
지역 컴포넌트는 새 인스턴스를 생성할 때마다 등록해줘야 한다 

 

 

 

 

 

 


 

 

 

 

뷰 컴포넌트 통신


컴포넌트 간 통신과 유효 범위

뷰(Vue.js) 는 컴포넌트로 화면을 구성하므로 같은 웹 페이지라도 데이터를 공유 x 

컴포넌트마다 자체적으로 고유한 유효 범위(scope)를 갖기 때문이다

"각 컴포넌트의 유효 범위가 독립적이기 때문에 다른 컴포넌트의 값을 직접적으로 참조할 수 없다"

 

 

 

 

🍀 2개의 컴포넌트를 등록하고, 한 컴포넌트에서 다른 컴포넌트의 값을 직접 참조하는 예제 

<html>
    <head>
    	<title> Vue Compoenet  </title>
    </head>
    <body>
    	<div id="app">
            <my-component1></my-component1> 
            <my-component2></my-component2> 
        </div>
        
				<script src="https://cdn.jsdelivr.net/npm/vue@2.6.0"></script>

        <script>
     	// 첫 번째 컴포넌트 내용 
        var cmp1 = {
        // 컴포넌트 내용
        template: '<div> 첫 번째 지역 컴포넌트 등록 : {{ cmp1Data }}</div>',
	data: function() {
	   return {
	   cmp1Data : 100
	   }
	  }
      };
	  // 두 번째 컴포넌트 내용 
	  var cmp2 = {
       // 컴포넌트 내용
      template: '<div> 두 번째 지역 컴포넌트 등록 : {{ cmp2Data }} </div>',
	data: function() {
	return {
		mp2Data : cmp1.data.cmp1Data
		}
           }
         };
        	
         new Vue({
           el: '#app',
			//지역 컴포넌트 등록
           components: {
              'my-component1': cmp1,
	      'my-component2': cmp2,
           }
         });
            
          
        </script>
    </body>
</html>

{{ cmp2Data }} 에 아무 값도 출력되지 않은 이유는 my-component2 에서 my-component1의 값을 직접 참조할 수 없기 때문

 

 

따라서 뷰 프레임워크 자체에서 정의한 컴포넌트 데이터 전달 방법을 따라야 한다 


 

1.  상 하위 컴포넌트 관계

트리 구조에서 부모 노드, 자식 노드처럼 컴포넌트 간의 관계가 부모, 자식으로 이루어진 컴포넌트를 의미

 

상위에서 하위로는 props 라는 특별한 속성을 전달

하위에서 상위로는 기본적으로 이벤트만 전달할 수 있다

💡 이벤트와 함께 데이터를 전달하고 싶은 경우에는 이벤트의 두 번째 인자 값으로 전달하거나, 이번트 버스(Event Bus)를 활용하는 방법이 있다

 

 

📌 상위에서 하위 컴포넌트로 데이터 전달하기

props 속성

상위 컴포넌트에서 하위 컴포넌트로 데이터를 전달할 때 사용하는 속성

  • 위 컴포넌트의 속성에 props 정의한다 
Vue.component('child-component', {
	props: ['props 속성 이름'],
});

 

  • 상위 컴포넌트의 HTML 코드에 등록된 child-component 컴포넌트 태그에 v-bind 속성을 추가
<child-component v-bind:props 속성이름="상위 컴포넌트의 data 속성"></child-component>

 

뷰 인스턴스에 child-component를 등록한 모습

이렇게 인스턴스에 새로운 컴포넌트를 등록하면 기존에 있는 컴포넌트는 상위 컴포넌트(부모)가 되고, 새로 등록된 컴포넌트는 하위(자식)컴포넌트가 된다 
새 컴포넌트를 등록한 인스턴스를 최상위 컴포넌트(Root Component)라고 부른다 

 

 

 

📌 하위에서 상위 컴포넌트로 이벤트 전달하기

 

이벤트를 발생시켜(event emit) 상위 컴포넌트에 신호를 보낸다 

상위 컴포넌트에서 하위 컴포넌트의 특정 이벤트가 발생하기를 기다리고 있다가 하위 컴포넌트에서 특정 이벤트가 발생하면 상위 컴포넌트에서 해당 이벤트를 수신하여 상위 컴포넌트의 메서드를 호출한다 

 

 

  • $emit()v-on: 속성 사용하여 구현
// 이벤트 발생
this.$emit('이벤트명');

// 이벤트 수신
<child-component v-on:이벤트명 = "상위 컴포넌트의 메서드명"></child-component>
일반적으로 $emit() 을 호출하는 위치는 하위 컴포넌트의 특정 메서드 내부 이다 
따라서 $emit()을 호출할 때 사용하는 this는 하위 컴포넌트를 가리킨다 

 

 

 

 

📌  같은 레벨의 컴포넌트 간 통신

 

 

같은 상위 컴포넌트를 가지는 2개의 하위 컴포넌트
뷰는 상위에서 하위로만 데이터를 전달해야 하는 기본적인 통신 규칙을 따르기 때문에
바로 옆 컴포넌트에 값을 전달하려면 하위에서 공통 상위 컴포넌트로 이벤트를 전달한 후 공통 상위 컴포넌트에서 2개의 하위 컴포넌트에 props를 내려보내야 한다 

( 컴포넌트 고유의 유효 범위 때문)

 

 

 

 

📌  관계 없는 컴포넌트 간 통신 - 이벤트 버스

 이벤트 버스

2개의 컴포넌트 간에 데이터를 주고받을 수 있는 방법 

 

 

 

 

최하위에 있는 하위 컴포넌트 B에서 상위 컴포넌트 A로 데이터를 전달하려면??

뷰에서 제시하는 기본적인 컴포넌트 통신 방식을 생각했을 때 
하위 컴포넌트 B, 상위 컴포넌트 B, 최상위 컴포넌트를 거쳐 상위 컴포넌트 A까지 가야한다 
하지만 웹 앱이 커져 컴포넌트가 많아지면 이런 식의 데이터 전달 방식은 매우 번거롭다

이럴 경우, 이벤트 버스를 활용하면 중간 컴포넌트를 거치지 않고 
하위 컴포넌트 B에서 상위 컴포넌트 A 로 바로 데이터 전달할 수 있어 편리하다 

 

 

 

이벤트 버스 형식

애플리케이션 로직을 담는 인스턴스와는 별개로 새로운 인스턴스 1개 더 생성, 새 인스턴스를 이용하여 이벤트를 보내고 받는다 

  • 보내는 컴포넌트에서는 .$emit()
  • 받는 컴포넌트에서는 .$on() 구현

 

// 이벤트 버스를 위한 추가 인스턴스 1개 생성
var eventBus = new Vue();


// 이벤트를 보내는 컴포넌트
methods {
	메서드명: function() {
    	eventBus.$emit('이벤트명', 데이터);
    }
}

// 이벤트를 받는 컴포넌트
methods: {
	created: function() {
    	eventBus.$on('이벤트명', function(데이터) {
        	...
        });
    }
}

 

 

 

💡 이벤트 버스를 활용하면 props 속성을 이용하지 않고도 원하는 컴포넌트 간에 직접적으로 데이터를 전달할 수 있어 편리하지만 컴포넌트가 많아지며 어디서 어디로 보냈는지 관리가 되지 않는 문제가 발생한다
이 문제를 해결하려면 vuex 같은 상태 관리 도구가 필요하다 
728x90
반응형

'Vue.js' 카테고리의 다른 글

[Vue.js] Options API vs Composition API  (0) 2023.02.12
[Vue.js] 컴포넌트에 대해  (0) 2023.02.09
[Vue.js] Vue Instance  (0) 2022.05.01
[Vue.js] Vue.js 개발 환경 설정  (0) 2022.04.30
[Vue.js] Vue.js 란  (0) 2022.04.30