์ฐธ๊ณ ๋ก Vue.js์ ๋ํด์ ์ ๋ชจ๋ฆ ๋๋ค.
์๋ฌด๊ฑฐ๋ ๋ง ํด๋ณด๋ ์ค์ด๊ณ ์ณ์ ์ ๋ณด์ธ์ง ์ ๋ ๋ชจ๋ฆ ๋๋ค!
props์ emit๋ฅผ ์ฌ์ฉํ์ฌ
๋ถ๋ชจ ์ปดํฌ๋ํธ์ ์์ ์ปดํฌ๋ํธ ์ฌ์ด์
๋ฐ์ดํฐ๋ฅผ ์ ๋ฌํด๋ณด์.
props
- ๋ถ๋ชจ ์ปดํฌ๋ํธ๊ฐ ์์ ์ปดํฌ๋ํธ์๊ฒ ๋ฐ์ดํฐ๋ฅผ ์ ๋ฌํ๋ค.
- ๋ช ์์ ์ธ props ์ ์ธ์ด ํ์ํ๋ค.
- <script setup>์ ์ฌ์ฉํ ๋๋ defineProps() ๋งคํฌ๋ก๋ฅผ ์ฌ์ฉํ์ฌ props๋ฅผ ์ ์ธํ๋ค.
- <script setup>์ด ์๋ ์ปดํฌ๋ํธ์ ๊ฒฝ์ฐ props ์ต์ ์ ์ฌ์ฉํ์ฌ ์ ์ธํ๋ค.
- ์ ์ธ ๋ฐ ํ ํ๋ฆฟ ์ฐธ์กฐ ์ camelCase๋ก ์ฌ์ฉํ๋ค.
- ์์ ์ปดํฌ๋ํธ ์ ๋ฌ ์ kebab-case๋ฅผ ์ฌ์ฉํ๋ค. (HTML ์์ฑ ํ๊ธฐ๋ฒ)
defineProps์ ์ฝ๋ ์์ _ ๊ฐ์ฒด๋ฅผ ์ฌ์ฉํ ์ ์ธ(๊ถ์ฅ)
<script setup>
const { msg, count } = defineProps({
msg: { type: String, required: true },
count: { type: Number, default: 0 },
})
</script>
defineProps์ ์ฝ๋ ์์ _ ๋ฌธ์์ด ๋ฐฐ์ด์ ์ฌ์ฉํ ์ ์ธ
<script setup>
defineProps(['myMsg'])
</script>
props์ ์ฝ๋ ์์ _ ๊ฐ์ฒด๋ฅผ ์ฌ์ฉํ ์ ์ธ(๊ถ์ฅ)
<script>
props: {
msg: { type: String, required: true },
count: { type: Number, default: 0 },
}
</script>
emit
- $emit()๋ ์์ ์ปดํฌ๋ํธ๊ฐ ์ด๋ฒคํธ๋ฅผ ๋ฐ์ํค์ ๋ถ๋ชจ ์ปดํฌ๋ํธ๋ก ๋ฐ์ดํฐ๋ฅผ ์ ๋ฌํ๋ ์ญํ ๋ฉ์๋์ด๋ค.
- ์ปดํฌ๋ํธ์์ ๋ฐ์์ํค๋ ์ปค์คํ ์ด๋ฒคํธ๋ฅผ ์ ์ธํ๋ค.
- ๋ฐ์์ํค๋ ์ด๋ฒคํธ๋ ๋ ๊ฐ์ง ํํ๋ก ์ ์ธ ๊ฐ๋ฅํ๋ค.
- ๋ฌธ์์ด ๋ฐฐ์ด์ ์ฌ์ฉํ๋ ๊ฐ๋จํ ํํ
- ๊ฐ ์์ฑ ํค๊ฐ ์ด๋ฒคํธ ์ด๋ฆ์ด๊ณ ๊ฐ์ด null ๋๋ ์ ํจ์ฑ ๊ฒ์ฌ ํจ์์ธ ๊ฐ์ฒด ํํ
emit ์ฝ๋ ์์
์์ ์ปดํฌ๋ํธ
<script>
methods: {
showText() {
this.$emit('show', 'lightpink')
}
</script>
<template>
<button @click="showText()" class="c-btn"> ๋ถ๋ชจ ์ปดํฌ๋ํธ ์์ ๋ฐ๊พธ๊ธฐ </button>
</template>
๋ถ๋ชจ ์ปดํฌ๋ํธ
methods: {
show(color) {
this.backColor = color;
},
๊ฐ๋จํ๊ฒ ํ๋ก์ ํธ ๋ง๋ค๊ธฐ
- ๋ถ๋ชจ ์ปดํฌ๋ํธ์์ ๋ฒํผ์ ๋๋ฅด๋ฉด ์์ ์ปดํฌ๋ํธ๊ฐ ๋ฑ์ฅํ๋ค. (props ์ฌ์ฉ)
- ์์ ์ปดํฌ๋ํธ์์ ๋ฒํผ์ ๋๋ฅด๋ฉด ๋ถ๋ชจ ์ปดํฌ๋ํธ์ ๋ฐฐ๊ฒฝ์์ด ํํฌ์์ผ๋ก ๋ฐ๋๋ค. (emit ์ฌ์ฉ)
ํ๋ฉด
App.vue ์ฝ๋
- template ์ฝ๋
<template>
<div class="app" :style="{backgroundColor: backColor}">
<button class="p-btn" @click="child"> ์์ ์ปดํฌ๋ํธ ๋ํ๋๊ธฐ </button>
<ChildComponent :open="open" @show="show"/>
</div>
</template>
:style์ v-bind:์ ์ถ์ฝํ์ผ๋ก v-bind:style์ด ์๋, :style๋ก ๋ฐ๋ก ์ฌ์ฉํ ์ ์๋ค. v-bind๋ ํ๋ ์ด์์ ์์ฑ ๋๋ ์ปดํฌ๋ํธ prop์ ํํ์์ ๋์ ์ผ๋ก ๋ฐ์ธ๋ฉํ ๋ ์ฌ์ฉํ๋ค. ์ฌ๊ธฐ์ :style์ ์์ฑ์ ๋ฐ์ธ๋ฉํ ๋์ธ, ์์ฑ์ ๋ด๋ ค๋ณด๋ผ๋ ์ฌ์ฉํ๋ค.(DOM์ผ๋ก ๋ด๋ ค๋ณด๋)
์์ ์ปดํฌ๋ํธ๋ emit์ผ๋ก ์ด๋ค ๋ฉ์๋๋ฅผ ์คํ์ํฌ์ง์ ์ปฌ๋ฌ๋ช ์ ์ ๋ฌํ ๊ฒ์ด๋ค. ๊ทธ๋ฌ๋ฉด ๋ถ๋ชจ ์ปดํฌ๋ํธ์์ show๋ผ๋ ๋ฉ์๋๊ฐ ์คํ๋๋ค. show๋ผ๋ ๋ฉ์๋๋ ์ปฌ๋ฌ๋ฅผ ๋ฐ์ backColor๋ฅผ ๋ฐ๊พผ๋ค. ๊ทธ๋ฌ๋ฉด :style์ ๋ฐ์ํ์ด๊ธฐ ๋๋ฌธ์ backColor๋ฅผ backgroundColor์ ๋ฃ์ด ์ฐ๋ฆฌ๊ฐ ๋ค์์ ์์ฑํ style๋ณด๋ค ๋ ๋จผ์ DOM์ ์ฌ๋ผ๊ฐ๋ค.
๋ถ๋ชจ ์ปดํฌ๋ํธ์ ๋ฒํผ์ ๋ง๋ค๊ณ ๊ทธ ๋ฒํผ์ ๋๋ฅด๋ฉด ์์ ์ปดํฌ๋ํธ๊ฐ ๋ํ๋๋๋ก ํ ๊ฒ์ด๋ค. p-btn ๋ฒํผ์ ๋ง๋ค๊ณ ๊ทธ ๋ฒํผ์ ํด๋ฆญํ๋ฉด child๋ผ๋ ๋ฉ์๋๊ฐ ์คํ๋๋๋ก ํ๋ค.
์์ ์ปดํฌ๋ํธ ์ด๋ฆ์ ChildComponent์ด๋ค. open์ด๋ ๋ฐ์ดํฐ๋ script์์ false๋ก ๊ธฐ๋ณธ๊ฐ์ ์ค์ ํ ๊ฒ์ด๋ค. ๊ทธ๋์ ์ฒ์ ํ๋ฉด์ ๋ค์ด๊ฐ๋ฉด ์์ ์ปดํฌ๋ํธ๋ ๋ณด์ด์ง ์์ ๊ฒ์ด๋ค. p-btn์ ๋๋ฅด๋ฉด child ๋ฉ์๋๊ฐ ์คํ๋๋๋ก ๋ง๋ค์๋๋ฐ, ์ด child ๋ฉ์๋๋ open๊ฐ์ ๋ฐ๋๋ก ๋ฐ๊ฟ์ฃผ๋๋ก ๋ง๋ค ๊ฒ์ด๋ค. ๊ทธ๋์ p-btn์ ๋๋ฅด๋ฉด false ๊ฐ์ด๋ open์ด true๋ก ๋ฐ๋๋ค.
๊ทธ๋ฌ๋ฉด ์ด๋ฐ open ๊ฐ์ ChildComponent์ ๋ณด๋ด์ผํ๋ค. ๊ทธ๋์ ์ด๋ฒ์ :open์ ์ฌ์ฉํ๋ค. ์๊น ์ฒ์ ์ค๋ช ํ์ ๋, v-bind๋ ํ๋ ์ด์์ ์์ฑ ๋๋ ์ปดํฌ๋ํธ prop์ ํํ์์ ๋์ ์ผ๋ก ๋ฐ์ธ๋ฉํ ๋ ์ฌ์ฉํ๋ค๊ณ ํ๋ค. :open์ ์์ ์ปดํฌ๋ํธ๋ก ๋ด๋ ค๋ณด๋ด์ props๋ฅผ ํตํด ํด๋น ๊ฐ์ ๋ฐ๊ฒ ํ ๊ฑฐ๋๊น, ์ด๋ฒ์ prop์ ํํ์์ ๋์ ์ผ๋ก ๋ฐ์ธ๋ฉํ๊ธฐ ์ํด ์ฌ์ฉํ๋ค.
@show๋ v-on์ ์ฌ์ฉํ ๊ฒ์ผ๋ก, ๊ฐ์ ์ฌ๋ ค๋ณด๋ด๋ ์ญํ ์ ํ๋ค. @v-on:eventName="ํธ๋ค๋ฌ"๋ก ํ๊ธฐํ๋ฉฐ, ์ถ์ฝํ์ @eventName="ํธ๋ค๋ฌ"๊ฐ ๋๋ค. ์์ ์ปดํฌ๋ํธ์์ emit์ผ๋ก ๋ถ๋ชจ ์ปดํฌ๋ํธ์ ๋ฐ์ดํฐ๋ฅผ ์ ๋ฌํ๊ธฐ์ v-on์ ์ด๋ค.
- script ์ฝ๋
<script>
import ChildComponent from "@/components/ChildComponent.vue";
export default {
name: "App",
components: {ChildComponent},
data() {
return {open:false, backColor:'lemonchiffon'}
},
methods: {
show(color) {
this.backColor = color;
},
child() {
this.open = !this.open;
}
}
}
</script>
App.vue์ ChildComponent๊ฐ ๋ณด์ฌ์ผํ๋๊น, import ํด์ค๋ค.
data์ open ๊ฐ์ false๋ก ์ค์ ํด์ฃผ๊ณ , backColor์ ์ํ๋ ์ปฌ๋ฌ๋ฅผ ์ ๋ ฅํ๋ค.
์ด์ ๋ฉ์๋๋ฅผ ์ค์ ํ ๊ฒ์ด๋ค. ๋ฉ์๋ show( )๋ color๋ฅผ ๋ฐ์์ backColor๋ฅผ ๋ณ๊ฒฝํ๋ค. ๊ทธ๋ฌ๋ฉด lemonchiffon์ด๋ ์ปฌ๋ฌ๊ฐ ๋ฐ๋ ๊ฒ์ด๋ค. ๊ทธ๋ฆฌ๊ณ :style์ ํตํด ๋ฐฐ๊ฒฝ์ปฌ๋ฌ๊ฐ ๋ณ๊ฒฝ๋๋ค.
๋ฉ์๋ child( )๋ p-btn ๋ฒํผ์ด ํด๋ฆญ๋ ๋ ๋ง๋ค ๊ฐ์ด ๋ฐ์ ๋๋ค. false -> true๋ก true -> false๋ก ๋ณ๊ฒฝ๋๋ค. ์ด ๋ฐ๋ ๊ฐ์ ChildComponent๋ก ๋์ด๊ฐ๋ค.
- sytle ์ฝ๋
<style>
.app {
position: relative;
width: 100vw;
height: 100vh;
}
.p-btn {
position: absolute;
width: 30%;
height: 10%;
top: 50%;
left: 75%;
transform: translate(-50%, -50%);
text-align: center;
font-size: 1.1rem;
z-index: 2;
cursor: pointer;
}
</style>
ChildComponent.vue ์ฝ๋
- template ์ฝ๋
<template>
<div class="child" :class="{open:open}">
<button @click="changeColor()" class="c-btn"> ๋ถ๋ชจ ์ปดํฌ๋ํธ ์์ ๋ฐ๊พธ๊ธฐ </button>
</div>
</template>
child ํด๋์ค๊ฐ ๊ฐ์ฅ ์์์ ์๋ ํด๋์ค๋ก ChildComponent์ ์ ์ฒด ํ๋ฉด์ ์ด์ผ๊ธฐํ๋ค. ์ด ์ ์ฒด ํ๋ฉด์ open์ ๊ฐ์ด true๊ฐ ๋๋ฉด ๋ณด์ด๋๋ก ํ๊ณ , false๋ฉด ๋ณด์ด์ง ์๋๋กํ๋ค. script์์ .open์ ํตํด ํ๋ฉด์ ์์น๋ฅผ ์กฐ์ ํ๋ค. false์ด๋ฉด ํ๋ฉด ๋ฐ๊นฅ์ ์์นํ๊ณ true๋ฉด .child.open์ ์ค์ ํ ๊ฐ์ผ๋ก ์ธํด ํ๋ฉด ์์ชฝ์ ๋ณด์ด๋๋ก ํ๋ค.
c-btn์ ๋ง๋ค๊ณ ์ด ๋ฒํผ์ ํด๋ฆญํ๋ฉด changeColor ๋ฉ์๋๊ฐ ์คํ๋๋๋ก ํ๋ค.
- script ์ฝ๋
<script>
export default {
name: 'ChildComponent',
props: {
open: {
type: Boolean,
required: true,
},
},
methods: {
changeColor() {
this.$emit('show', 'lightpink')
}
},
}
</script>
๋ถ๋ชจ ์ปดํฌ๋ํธ๋ก ๋ฐ์ open ๊ฐ์ props๋ก ๋ฐ์๋ค. open์ ๊ฐ์ boolean ํํ์ฌ์ผํ๊ณ , true๊ฐ ๋์ด์ผ open์ด ์คํ๋๋๋ก ํ๋ค.
๋ฉ์๋ changeColor๋ $emit์ผ๋ก ๋ถ๋ชจ ์ปดํฌ๋ํธ์๊ฒ show๋ผ๋ ์ปค์คํ ์ด๋ฒคํธ๋ฅผ ๋ฐํํ๊ณ lightpink๊ฐ ์ฒซ๋ฒ์งธ ์ธ์๋ก ์ ๋ฌ๋๋ค. ๋ถ๋ชจ ์ปดํฌ๋ํธ์ ChildComponent @show="show"๋ฅผ ์ ์์๋ค. ๊ทธ๋ฌ๋ฉด ๋ถ๋ชจ๊ฐ ์ด ์ด๋ฒคํธ๊ฐ ๋ฐํ๋ ๊ฑธ ์๊ณ ํธ๋ค๋ฌ๋ฅผ ์คํ์ํจ๋ค.
- style ์ฝ๋
<style>
.child {
position: relative;
width: 50vw;
height: 100vh;
top: 0;
right:0;
background-color: cornflowerblue;
transform: translateX(-100%);
transition: transform 0.4s cubic-bezier(.71,1.7,.58,.98);
}
// open์ true๊ฐ ์ค๋ฉด transform ๊ฐ์ด ๋ฐ๋๋ค.
.child.open {
transform: translateX(0%);
}
.c-btn {
position: absolute;
width: 60%;
height: 10%;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
text-align: center;
font-size: 1.1rem;
cursor: pointer;
}
</style>
- ์ฃผ์ํ๊ธฐ
๋ง์ฝ์ ๋ถ๋ชจ ์ปดํฌ๋ํธ์ ์์ ์ปดํฌ๋ํธ์ ๋ฒํผ ์ด๋ฆ์ด ๊ฐ์ ๊ฒฝ์ฐ ๋ฒํผ์ด ์๋ํ์ง ์์ผ๋ ๊ผญ ๋ฒํผ์ ์ด๋ฆ์ ๋ค๋ฅด๊ฒ ์ค์ ํด์ฃผ์!