SFC(single file application)
✔️컴포넌트 (Component)란?
- Vue의 가장 '강력한 기능' 중 하나
- HTML Element를 확장하여 재사용 가능한 코드를 캡슐화
- Vue Component는 Vue Instance이기도 하기 때문에 모든 옵션 객체를 사용
- Life Cycle Hook 사용 가능
- 전역 컴포넌트와 지역 컴포넌트
✔️전역컴포넌트와 지역 컴포넌트
📌전역 컴포넌트
: 전역 컴포넌트를 등록하려면, Vue.component('tagName',{ options}),
html에서 컴포넌트를 불러올 때 권장하는 컴포넌트 이름 : 케밥 표기법 ( 전부 소문자, - ),
전역이라서 다른 Vue영역에서도 사용 가능
<body>
<div id="app1">
<global-com></global-com>
<global-com></global-com>
</div>
<div id="app2">
<global-com> </global-com>
<global-com></global-com>
</div>
<script>
//전역 컴포넌트
Vue.component('GlobalCom', {
template: `<h2>전역 컴포넌트입니다.</h2>`,
}),
new Vue({
el: '#app1',
});
new Vue({
el: '#app2',
});
</script>
</body>
📌지역 컴포넌트
: Vue의 해당 el영역 안에서만 사용 가능
<body>
<div id="app1">
<local-com></local-com>
<local-com></local-com>
</div>
<div id="app2">
<local-com></local-com>
<local-com></local-com>
</div>
<script>
new Vue({
el: '#app1',
components: {
'LocalCom': {
template: `<h2>지역 컴포넌트입니다.</h2>`,
}
},
});
new Vue({
el: '#app2',
});
</script>
</body>
✔️컴포넌트 template
- div가 저절로 만들어진다?=꼭 적어줘야 하는 것(탬플릿 안에는 무조건 1개의 div만 가능)
- template의 id를 적을 수 있다
- 컴포넌트도 Vue인스턴스화 시킬 수 있어서 data 가능하다(컴포넌트 안에서 data를 쓸 경우 무조건 function형태로 써야 함)
<body>
<div id="app">
<my-comp></my-comp>
</div>
<template id="MyTem">
<div>
<h2>{{msg}}</h2>
</div>
</template>
<script>
Vue.component('MyComp', {
template: '#MyTem',
data() {
return {
msg: 'hello component',
};
},
});
new Vue({
el: '#app',
});
</script>
</body>
Vue 컴포넌트 안에서 탬플릿을 길게 쓸 수 없으니 밖으로 뺀 거고, 그게 다시 탬플릿 안으로 들어가고 전체 완성된 컴포넌트가 다시 완성된다.
✔️Component data 공유 문제
버튼을 클릭하면 count가 올라가는 형태가 3개 똑같이 생긴다. 근데 각각 다르게 count가 되는 게 아니고 똑같이 카운트가 올라간다. 이유: 전역 변수인 num을 3개의 컴포넌트가 공유해서 쓰기 때문
해결책: 전역 변수가 아닌 지역변수로 바꿔주기
<body>
<h2>컴포넌트 데이터 공유 문제 해결</h2>
<div id="app">
<count-view></count-view>
<count-view></count-view>
<count-view></count-view>
</div>
<template id="CountView">
<div>
<span>{{ count }}</span>
<button @click="count++">클릭</button>
</div>
</template>
<script>
Vue.component('CountView', {
template: '#CountView',
data() {
return {
count: 0,
};
},
});
new Vue({
el: '#app',
});
</script>
</body>
✔️컴포넌트간 통신
: 상위 컴포넌트와 하위컴포넌트 간의 data전달 방법
- 부모 → 자식 : props라는 특별한 속성을 전달(Pass Props)
- 자식 → 부모 : event로만 전달 가능(Emit Event)
📌상위에서 하위 컴포넌트로 data 전달
- 하위 컴포넌트는 상위 컴포넌트의 값을 직접 참조 불가능
- data와 마찬가지로 props 속성의 값을 template에서 사용이 가능
props 여러개 넘길 수 있으니까 객체타입+상세설정도 가능(권장)
<body>
<div id="app">
<h2>props test</h2>
<child-component propsdata="안녕하세요"></child-component>
</div>
<script>
//하위 컴포넌트
Vue.component('childComponent', {
props: ['propsdata'],
template: '<span>{{ propsdata }}</span>',
});
new Vue({
el: '#app',
});
</script>
</body>
📌input창이랑 props 데이터의 연결하기:v-bind연결하기
<body>
<div id="app">
<h2>props test</h2>
<input type="text" v-model="msg">
<child-component :propsdata="msg"></child-component>
</div>
<script>
//하위 컴포넌트
Vue.component('childComponent', {
props: ['propsdata'],
template: '<span>{{propsdata}}</span>',
});
new Vue({
el: '#app',
data() {
return {
msg: "",
}
}
});
</script>
</body>
📌동적 props : 상위에서 하위로 넘겨줄 때 이름자체로 넘겨주는것과 상위 컴포넌트에 있는 data를 넘겨줄 때는 v-bind써주기
<body>
<div id="app">
<child-comp area="서울" v-bind:msg="msg[parseInt(Math.random() * 5)]"></child-comp>
<child-comp area="대전" v-bind:msg="msg[parseInt(Math.random() * 5)]"></child-comp>
<child-comp area="대구" v-bind:msg="msg[parseInt(Math.random() * 5)]"></child-comp>
<child-comp area="부산" v-bind:msg="msg[parseInt(Math.random() * 5)]"></child-comp>
<child-comp area="광주" v-bind:msg="msg[parseInt(Math.random() * 5)]"></child-comp>
</div>
<template id="ChildComp">
<div>
<h2>SSAFY {{area}}지역 {{msg}}</h2>
</div>
</template>
<script>
Vue.component('childComp', {
props: ['area', 'msg'],
template: '#ChildComp',
});
new Vue({
el: '#app',
data: {
msg: ['최고', '굿', '좋아', '짱', '멋지다'],
},
});
</script>
</body>
📌동적 props for문 사용
<body>
<div id="app">
<child-comp v-for="(area, i) in areas" :key="i" :area="area" :msg="msg[parseInt(Math.random() * 5)]">
</child-comp>
</div>
<template id="ChildComp">
<div>
<h2>SSAFY {{area}}지역 {{msg}}</h2>
</div>
</template>
<script>
Vue.component('childComp', {
props: {
'area': String,
'msg': {
type: String, require: true
}
},
template: '#ChildComp',
});
new Vue({
el: '#app',
data: {
areas: ['서울', '대전', '대구', '부산', '광주'],
msg: ['최고', '굿', '좋아', '짱', '멋지다'],
},
});
</script>
</body>
📌객체로 props 전달하기
<body>
<h2>컴포넌트 객체 데이터 전달</h2>
<div id="app">
<member-view v-bind:member="user"></member-view>
</div>
<template id="MemberView">
<div>
<div>이름 : {{ member.name }}</div>
<div>나이 : {{ member.age }}</div>
<div>이메일 : {{ member.email }}</div>
</div>
</template>
<script>
Vue.component('memberView', {
props: ['member'],
template: '#MemberView',
});
new Vue({
el: '#app',
data() {
return {
user: {
name: '모두의 향연',
age: 100,
email: 'feastforall@tistory.com',
},
};
},
});
</script>
</body>
✔️사용자 정의 이벤트
: v-on 이벤트 리스너는 항상 자동으로 소문자 변환되기 때문에 v-on:myEvent 는 자동으로 v-on:myevent 로 변환된다. 이름이 my-event일 경우 myEvent 이벤트를 들을 수 없다.
[이벤트 발생]
vm.$emit(“이벤트명”, [… 파라미터]);
ex) vm.$emit(“speed”, 100);
[이벤트 수신]
vm.$on(“이벤트명”, 콜백함수( ){ });
ex) vm.$on(“speed”, function(speed) { });
<body>
<h2>사용자 정의 이벤트</h2>
<div id="app">
<button v-on:click="doAction">메시지전송</button>
<h2>{{message}}</h2>
</div>
<script>
new Vue({
el: '#app',
data: {
message: '',
},
methods: {
doAction() {
this.$emit('sendMsg', '안녕하세요 여러분');
},
},
created() {
this.$on('sendMsg', (msg) => {
alert(msg);
this.message = msg;
});
},
});
</script>
</body>
✔️하위에서 상위 컴포넌트로 event 전달
하위 컴포넌트에서 상위 컴포넌트가 지정한 이벤트를 발생 ($emit)
ex) this.$emit(“이벤트명”);
상위 컴포넌트는 하위 컴포넌트가 발생한 이벤트를 수신 (on)하여 data 처리
ex) <child v-on:이벤트명=“상위 컴포넌트 메소드명“></child>
<body>
<div id="app">
<h2>하위에서 상위 컴포넌트로 event 전달</h2>
<h2>총 투표수 : {{ total }}</h2>
<subject v-on:addtotcount="addTotalCount" title="코딩"></subject>
<subject v-on:addtotcount="addTotalCount" title="알고리즘"></subject>
</div>
<script>
Vue.component('Subject', {
template: '<button v-on:click="addCount"> {{title}} - {{ count }}</button>',
props: ['title'],
data: function () {
return {
count: 0,
};
},
methods: {
addCount: function () {
this.count += 1;
this.$emit('addtotcount');
},
},
});
new Vue({
el: '#app',
data: {
total: 0,
},
methods: {
addTotalCount: function () {
this.total += 1;
},
},
});
</script>
</body>
✔️비 상하위간 통신
: 비어 있는 Vue Instance 객체를 Event Bus로 사용
: 복잡해질 경우 상태관리 라이브러리인 Vuex 사용 권장
var bus = new Vue();
// 컴포넌트 A bus.$emit(‘id-selected’, 1);
// 컴포넌트 B bus.$on(‘id-selected’, function (id) { });
<body>
<div id="app">
<my-count></my-count>
<log></log>
</div>
<template id="myCount">
<div>
<input type="text" v-model.number="count" @keyup.enter="send" />
<button @click="send">보내기</button>
</div>
</template>
<template id="log">
<div>
<h2>{{count}}</h2>
<ul>
<li v-for="msg in list">{{msg}}</li>
</ul>
</div>
</template>
<script>
const bus = new Vue();
Vue.component('myCount', {
template: '#myCount',
data() {
return {
count: 0,
};
},
methods: {
send() {
bus.$emit('updateLog', this.count);
this.count = '';
},
},
});
Vue.component('Log', {
template: '#log',
data() {
return {
count: 0,
list: [],
};
},
methods: {
updateLog(data) {
this.count += data;
this.list.push(`${data}을 받았습니다.`);
},
},
created: function () {
bus.$on('updateLog', this.updateLog);
},
});
new Vue({
el: '#app',
});
</script>
</body>
'front-end > Vue.js' 카테고리의 다른 글
API로 아파트 리스트 가져오기 (0) | 2022.07.28 |
---|---|
axios 비동기처리, Promise, async, await (0) | 2022.07.20 |
Vue.js 이벤트 (0) | 2022.07.08 |
Vue.js 인스턴스 속성(methods, filter, computed, watch) (0) | 2022.07.07 |
Vue.js개요, 인스턴스, 디렉티브 (0) | 2022.07.07 |