Component
컴포넌트는 화면의 영역을 구분하여 개발할 수 있는 뷰의 기능이다.
컴포넌트 기반으로 화면을 개발하게 되면 코드의 재사용성이 올라가고 빠르게 화면을 제작할 수 있다.
어떻게 컴포넌트를 등록하고 쪼개는지에 대해 알아보자
<!-- HTML -->
<div id="app">
<!-- component 표시 -->
<app-header></app-header>
</div>
<!-- JavaScript -->
<script src="https://unpkg.com/vue@3/dist/vue.global.js"></script>
<script>
Vue.createApp({
// 인스턴스 옵션 속성 - 옵션 API
components: {
// '컴포넌트 이름': 컴포넌트 내용
"app-header": {
template: "<h1>컴포넌트 등록</h1>",
},
},
}).mount("#app");
</script>
컴포넌트 이름 : 컴포넌트 내용
이런 문법형태로 작성하면 컴포넌트가 등록된것
등록된 컴포넌트를 HTML에서 호출해주면 된다.
Root라는 컴포넌트 밑에 AppHeader가 바로 등록되는것을 볼 수 있다.
다음에 컴포넌트가 하나씩 등록될때 마다 이 밑으로 바로 연결된다.
컴포넌트 통신 방식
컴포넌트간에 어떻게 메시지를 주고받을건지 그 방법을 정의하는것이 컴포넌트 통신
props속성
컴포넌트간 데이터를 전달할 수 있는 컴포넌트 통신 방법
상위 컴포넌트에서 하위 컴포넌트로 내려보내는 데이터 속성으로 기억
<!-- HTML -->
<div id="app">
<!-- <app-header v-bind:프롭스이름="상위컴포넌트의 데이터이름"></app-header> -->
<app-header v-bind:title="appTitle"></app-header>
</div>
<!-- JavaScript -->
<script src="https://unpkg.com/vue@3/dist/vue.global.js"></script>
<script>
Vue.createApp({
data() {
return {
appTitle: "props 넘기기",
};
},
components: {
"app-header": {
template: "<h1>{{ title }}</h1>",
props: ["title"],
},
},
}).mount("#app");
</script>
1. app-header 컴포넌트가 등록되어있는 상태
2. Root에서 app-header로 데이터를 내릴 수 있게끔 props 정의를 한다. props: [ 'title' ]
3. Root에서 데이터를 정의해서 app-header로 데이터값을 내려주며 된다.
4. data()를 열고 객체를 반환해주는 형태로 만들어준다.
5. title로 보낼 문자열을 선언해준다 > appTitle : 내용
6. appTitle을 app-header라는 컴포넌트에 넘겨주면 된다
> v-bind: props 이름="상위컴포넌트의 데이터이름"
* v-bind : 태그 속성 값을 상황에 따라 변경되게 하고싶거나, 하위 컴포넌트로 값을 전달해주고 싶을때 사용
7. 화면에 props 출력하려면 콧수염괄호를 이용 {{ title }}
> 애플리케이션 인스턴스 안에 정의된 모든 값들은 콧수염괄호를 통해 표시될 수 있다.
Event 발생
컴포넌트 통신방법 중 하위컴포넌트에서 상위컴포넌트로 통신하는 방식
this.$emit을 이용해서 이벤트 명을 넣어주면 이벤트 발생이된다.
<!-- HTML -->
<div id="app">
<app-contents></app-contents>
</div>
<!-- JavaScript -->
<script src="https://unpkg.com/vue@3/dist/vue.global.js"></script>
<script>
var appContents = {
template: `
<p>
<button v-on:click="sendEvent">갱신</button>
</p>
`,
methods: {
sendEvent() {
this.$emit("refresh");
},
},
};
Vue.createApp({
components: {
// '컴포넌트 이름':컴포넌트 내용
"app-contents": appContents,
},
}).mount("#app");
</script>
1. 컴포넌트를 선언해준다 > 내용이 길어질것같아서 따로 appContents로 선언해준다.
2. 템플릿에 내용을 넣어줄건데 여러줄을 쓸 수 있게 백틱(`)을 사용
3. p태그 안에 '갱신'이라고 하는 버튼을 작성해준다.
4. "app-contents" : appContents 를 작성해서, 컴포넌트를 등록해줌
5. 화면에 표시하기위해서 div태그 안에 <app-contents>를 작성
6. 갱신버튼을 눌렀을때 Root의 값을 바꾸는 형태로 진행할건데
7. 버튼태그안에 v-on:click="sendEvent"를 넣어주고, sendEvent 메서드를 생성한다.
8. sendEvent() 메서드 안에 this.$emit(' ') 을 넣어주면 > 하위컴포넌트에서 상위컴포넌트로 쏘아 올리는 이벤트
갱신버튼을 누르면 refresh 이벤트 발생
이번엔 갱신버튼을 눌렀을때 동작이 있도록 만들자
상위컴포넌트에 동작을 추가한다.
<!-- HTML -->
<div id="app">
<!-- <app-contents v-on:이벤트이름="상위컴포넌트(Root) 메서드 이름"></app-contents> -->
<app-contents v-on:refresh="showAlert"></app-contents>
</div>
//Root Component
Vue.createApp({
methods: {
showAlert() {
alert("새로고침");
},
},
components: {
// '컴포넌트 이름':컴포넌트 내용
"app-contents": appContents,
},
}).mount("#app");
상위컴포넌트(Root)에 showAlert() 메서드를 추가
갱신버튼을 눌렀을때 상위컴포넌트가 호출되고, alert창이 띄어진다.
같은 컴포넌트 레벨 통신
컴포넌트 동작방식이 위에서 아래로 데이터가 흐르고, 아래에서 위로 이벤트가 흐르는 방식때문에
같은 컴포넌트 레벨에서 직접 소통이 불가능하다.
기본적인 코드
<!-- HTML -->
<div id="app">
<app-header></app-header>
<app-contents></app-contents>
</div>
<!-- JavaScript -->
<script src="https://unpkg.com/vue@3/dist/vue.global.js"></script>
<script>
var appHeader = {
data() {
return {
appTitle: "로그인하세여",
};
},
template: `<h1> {{appTitle}}</h1>`,
};
var appContents = {
template: `
<p>
<button>로그인</button>
</p>
`,
methods: {},
};
Vue.createApp({
components: {
"app-header": appHeader,
"app-contents": appContents,
},
}).mount("#app");
</script>
일단 이렇게 구현되고,
로그인버튼<appContents>을 눌렀을때 appHeader의 appTitle의 내용이 변경될수있게 작성해보자
var appContents = {
template: `
<p>
<button v-on:click="sendEvent">로그인</button>
</p>
`,
methods: {
sendEvent() {
this.$emit("login");
//로그인이벤트를 상위로 보냄
},
},
};
이렇게 올려주고, 위에서
<app-contents v-on:login="receive"></app-contents>
받고, 받을때 상위컴포넌트에서 receive메서드를 작성해준다.
Vue.createApp({
methods: {
receive() {
console.log("받았다");
},
},
components: {
"app-header": appHeader,
"app-contents": appContents,
},
}).mount("#app");
일단 잘 연결되는지 콘솔로 확인
console창에 '받았다'라고 잘 들어오는거 확인됐다.
Vue.createApp({
data() {
return {
message: "",
};
},
methods: {
receive() {
console.log("받았다");
this.message = "로그인 됨";
},
},
components: {
"app-header": appHeader,
"app-contents": appContents,
},
}).mount("#app");
상위컴포넌트(Root)에 올라오면 message를 반환해주게 data를 작성해주고,
(message의 초깃값은 빈값)
receive 즉 로그인버튼을 누르면 '로그인됨'이라는 메시지를 보내줄수있게 한다.
<!-- HTML -->
<div id="app">
<app-header v-bind:appTitle="message"></app-header>
<app-contents v-on:login="receive"></app-contents>
</div>
그럼 이제 appHeader에 등록을 해주는데 props 등록은 v-bind를 사용해준다.
props가 등록이 되었으니 이제 appHeader에 있는 데이터는 필요가없어졌고,
값을 받을 수 있게 props를 선언 appTitle을 연결해준다.
var appHeader = {
props: ["appTitle"],
template: `<h1> {{appTitle}}</h1>`,
};
attrs에 있는 apptitle은 빈값이고, 로그인버튼을 누르면 "로그인 됨"이라는 메시지가 나타난다.
근데 props의 appTitle과 attrs의 apptitle 두개로 나뉘는걸 볼 수 있다.
이렇게 된 이유는 props를 카멜케이스로 임의로 작성했는데 html에서 태그는 대소문자 구분이 되어있지 않기 때문에
제대로 인식을 못하는것이다!
<!-- HTML -->
<div id="app">
<app-header v-bind:app-title="message"></app-header>
<app-contents v-on:login="receive"></app-contents>
</div>
app-title로 변경 ( Vue의 규칙이라 이건 차차 익혀나가자 )
이제 제대로 인식했고 제대로 message가 출력되는걸 확인할 수 있다.
컴포넌트끼리 직접소통이 안되기때문에
올리고 내리고의 그 흐름을 제대로 파악하고 사용하는것이 중요한것같다.
'FE > Vue.js' 카테고리의 다른 글
[ Vue.js ] 싱글 파일 컴포넌트 (0) | 2024.05.08 |
---|---|
[ Vue 3 ] Template Syntax (0) | 2024.05.05 |
[ Vue 3 ] Instance, Methods, Directive(v-for) (0) | 2024.05.03 |
[ Vue 3 ] Reactivity (0) | 2024.05.02 |
[ Vue 3 ] 시작, 개발환경 설정( Vue CLI ) (0) | 2024.05.02 |