component
nested component
<template>
<h2>Page Title</h2>
</template>
<template>
<div>
<PageTitle />
</div>
</template>
<script>
import PageTitle from '../components/PageTitle'
export default {
components: [PageTitle]
}
</script>
props
<template>
<h2>{{title}}</h2>
</template>
<script>
export default {
props: {
title: {
type: String,
default: "페이지 제목입니다."
}
}
}
</script>
<template>
<div>
<PageTitle title="Nested Component" />
</div>
</template>
<script>
import PageTitle from '../components/PageTitle'
export default {
components: { PageTitle }
}
</script>
dynamic props
v-bind
를 이용하여 props 전달이 가능하다.
<page-title :title="title"
단방향 데이터 흐름
모든 props는 자식 속성과 부모 속성 사이에 아래로 단방향 바인딩(one-way-down binding)을 형성합니다. 부모 속성이 업데이트되면 자식으로 흐르지만 반대 방향은 아닙니다. 이렇게하면 하위 컴포넌트가 실수로 앱의 데이터 흐름을 이해하기 힘들게 만드는 상위 컴포넌트 상태 변경을 방지할 수 있습니다.
또한, 부모 컴포넌트가 업데이트될 때마다 자식 컴포넌트의 모든 prop들이 최신 값으로 새로고침됩니다. 즉, 하위 컴포넌트에서 prop를 변경하려고 시도해서는 안됩니다. 그렇게하면 Vue는 콘솔에서 경고합니다.
일반적으로 prop를 변경하려는 2가지 경우가 있습니다
- prop는 초기 값을 전달하는데 사용됩니다. 하위 컴포넌트는 나중에 prop값을 로컬 data속성으로 사용하려고 합니다. 이 경우 prop를 초기 값으로 사용하는 로컬 data 속성을 정의하는 것이 가장 좋습니다.
props: ['initialCounter'], data() { return { counter: this.initialCounter } }
- prop는 변환해야 하는 원시 값으로 전달됩니다. 이 경우 prop의 값을 사용하여 computed 속성을 정의하는 것이 가장 좋습니다.
props: ['size'], computed: { normalizedSize: function () { return this.size.trim().toLowerCase() } }
Prop 대소문자 구분 (camelCase vs kebab-case)
HTML 속성명은 대소문자를 구분하지 않으므로, 브라우저는 모든 대문자를 소문자로 해석합니다. 즉, DOM내 템플릿을 사용할 때 camelCase된 prop명은 kebab-case(하이픈으로 구분)된 해당 항목을 사용해야 합니다.
const app = Vue.createApp({})
app.component('blog-post', {
// JavaScript에서의 camelCase
props: ['postTitle'],
template: '<h3>{{ postTitle }}</h3>'
})
<!-- HTML에서의 kebab-case -->
<blog-post post-title="hello!"></blog-post>
부모 컴포넌트에서 자식 컴포넌트 이벤트 직접 발생시키기
this.$refs
로 ref로 설정 된 id를 통해서 해당 컴포넌트에 접근이 가능하다.
<template>
<button type="button" @click="childFunc" ref="btn">Click</button>
</template>
<script>
export default {
methods: {
childFunc() {
console.log("부모 컴포넌트에서 직접 발생시킨 이벤트")
}
}
}
</script>
<template>
<child-component @send-message="sendmessage" ref="child_component" />
</template>
<script>
import ChildComponent from './ChildComponent'
export default {
components: { ChildComponent },
mounted() {
this.$refs.child_component.$refs.btn.click()
}
}
</script>
자식 컴포넌트에서 부모 컴포넌트로 이벤트/데이터 전달
<template>
<button type="button" @click="childFunc" ref="btn">Click</button>
</template>
<script>
export default {
data() {
return {
message: 'Send Parent'
}
},
methods: {
childFunc() {
console.log("부모 컴포넌트에서 직접 발생시킨 이벤트")
},
callFromParent() {
console.log("부모 컴포넌트에서 직접 호출")
}
},
mounted() {
this.$emit('send-message', this.message)
}
}
</script>
<template>
<child-component @send-message="sendMessage" ref="child_component" />
</template>
<script>
import ChildComponent from './ChildComponent'
export default {
components: { ChildComponent },
mounted() {
this.$refs.child_component.$refs.btn.click()
this.$refs.child_component.callFromParent()
},
methods: {
sendMessage(data) {
console.log(data)
}
}
}
</script>
자식 컴포넌트에서 부모 컴포넌트로 이벤트 전달하기 위해서 $emit
을 사용하면 된다.
slot
유사한 모습의 컴포넌트를 재활용할 수 있는 방법으로 HTML의 형식을 고정해두고, 해당 Slot을 여러 컴포넌트에서 재사용할 수 있다.
<template>
<h2><slot></slot></h2>
</template>
<script>
export default {
props: {
title: {
type: String,
default: "페이지 제목입니다."
}
}
}
</script>
<template>
<div>
<PageTitle>{{title}}</PageTitle>
</div>
</template>
<script>
import PageTitle from '../components/PageTitle'
export default {
data() {
return {
title: "Nested Component!!"
}
},
components: { PageTitle }
}
</script>
named slot
<div class="container">
<header>
<slot name="header">
</header>
<main>
<slot>
</main>
<footer>
<slot name="footer">
</footer>
</div>
<base-layout>
<template v-slot:header>
<h1>Here might be a page title</h1>
</template>
<template v-slot:default>
<p>A paragraph for the main content.</p>
<p>And another one.</p>
</template>
<template v-slot:footer>
<p>Here's some contact info</p>
</template>
</base-layout>
name
을 갖지 않는 <slot>
은 묵시적으로 "default"라는 name을 갖습니다.
이름을 가진 slot에 컨텐츠를 제공하기 위해서는 <template>
엘리먼트에 v-slot
지시자를 사용합니다.v-slot
의 매개변수로는 각 slot의 이름을 전달합니다.
<base-layout>
<template v-slot:header>
<h1>Here might be a page title</h1>
</template>
<template v-slot:default>
<p>A paragraph for the main content.</p>
<p>And another one.</p>
</template>
<template #footer>
<p>Here's some contact info</p>
</template>
</base-layout>
v-slot
대신에 축약으로 #
도 사용 가능하다.
Provide/Inject
부모 컴포넌트에서 자식 컴포넌트로 데이터를 전달 해야 할때, depth가 깊어지는 경우 props를 불필요하게 전달 해야 하는데, 이 때 Provde / Inject를 통해 원하는 자식 컴포넌트에게 데이터를 전달 할 수 있다.
<template>
<ProvideInjectChild />
</template>
<script>
import ProvideInjectChild from './ProvideInjectChild'
export default {
components: {
ProvideInjectChild
},
data() {
return {
items: [
'A',
'B'
]
}
},
provide() {
return {
item: this.items
}
}
}
</script>
<script>
export default {
inject: ['item'],
mounted() {
console.log(this.item)
console.log(this.item[0])
}
}
</script>
'프로그래밍 > JavaScript' 카테고리의 다른 글
npm을 pnpm 으로 바꾸면서 발생한 문제점 (--no-install Not Found) (0) | 2023.03.23 |
---|---|
VueJS 학습 - TypeScript 사용 (0) | 2022.10.13 |
VueJS 학습 - Basic (0) | 2022.10.13 |
vuejs minimizer 설정 변경 (0) | 2022.09.16 |
vite build 오류 (0) | 2022.09.07 |