728x90
[목표]
1. props와 emit를 연달아 사용하여 자식의 자식의 자식... 에게
함수 혹은 데이터를 보내지 않고 다이렉트로 보내는 방법에 대해 익숙해져 보자
원래는 이런식으로 보낸다
하지만 provide & inject를 사용하면 다음 그림과 같다
수정 전과 후의 소스를 비교하여 연습하자
[수정전 - App.vue]
<template>
<div>
<active-element
:topic-title="activeTopic && activeTopic.title"
:text="activeTopic && activeTopic.fullText"
></active-element>
<knowledge-base :topics="topics" @select-topic="activateTopic"></knowledge-base>
</div>
</template>
<script>
export default {
data() {
return {
topics: [
{
id: 'basics',
title: 'The Basics',
description: 'Core Vue basics you have to know',
fullText:
'Vue is a great framework and it has a couple of key concepts: Data binding, events, components and reactivity - that should tell you something!',
},
{
id: 'components',
title: 'Components',
description:
'Components are a core concept for building Vue UIs and apps',
fullText:
'With components, you can split logic (and markup) into separate building blocks and then combine those building blocks (and re-use them) to build powerful user interfaces.',
},
],
activeTopic: null,
};
},
methods: {
activateTopic(topicId) {
this.activeTopic = this.topics.find((topic) => topic.id === topicId);
},
},
};
</script>
<style>
* {
box-sizing: border-box;
}
html {
font-family: sans-serif;
}
body {
margin: 0;
}
section {
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.26);
margin: 2rem auto;
max-width: 40rem;
padding: 1rem;
border-radius: 12px;
}
ul {
list-style: none;
margin: 0;
padding: 0;
display: flex;
justify-content: center;
}
li {
border-radius: 12px;
border: 1px solid #ccc;
padding: 1rem;
width: 15rem;
margin: 0 1rem;
display: flex;
flex-direction: column;
justify-content: space-between;
}
h2 {
margin: 0.75rem 0;
text-align: center;
}
button {
font: inherit;
border: 1px solid #c70053;
background-color: #c70053;
color: white;
padding: 0.75rem 2rem;
border-radius: 30px;
cursor: pointer;
}
button:hover,
button:active {
background-color: #e24d8b;
border-color: #e24d8b;
}
</style>
[수정전 KnowledgeBase.vue]
<template>
<section>
<h2>Select a Topic</h2>
<knowledge-grid :topics="topics" @select-topic="$emit('select-topic', $event)"></knowledge-grid>
</section>
</template>
<script>
export default {
props: ['topics'],
emits: ['select-topic'],
};
</script>
[수정전 KnowledgeGrid.vue]
<template>
<ul>
<knowledge-element
v-for="topic in topics"
:key="topic.id"
:id="topic.id"
:topic-name="topic.title"
:description="topic.description"
@select-topic="$emit('select-topic', $event)"
></knowledge-element>
</ul>
</template>
<script>
export default {
props: ['topics'],
emits: ['select-topic']
};
</script>
[수정전 KnowledgeElement.vue]
<template>
<li>
<h3>{{ topicName }}</h3>
<p>{{ description }}</p>
<button @click="$emit('select-topic', id)">Learn More</button>
</li>
</template>
<script>
export default {
props: ['id', 'topicName', 'description'],
emits: ['select-topic'],
};
</script>
[수정전 ActiveElement.vue]
<template>
<section>
<h2>{{ topicTitle }}</h2>
<p>{{ text }}</p>
</section>
</template>
<script>
export default {
props: ['topicTitle', 'text'],
};
</script>
[수정전 main.js]
import { createApp } from 'vue';
import App from './App.vue';
import ActiveElement from './components/ActiveElement.vue';
import KnowledgeBase from './components/KnowledgeBase.vue';
import KnowledgeElement from './components/KnowledgeElement.vue';
import KnowledgeGrid from './components/KnowledgeGrid.vue';
const app = createApp(App);
app.component('active-element', ActiveElement);
app.component('knowledge-base', KnowledgeBase);
app.component('knowledge-element', KnowledgeElement);
app.component('knowledge-grid', KnowledgeGrid);
app.mount('#app');
[수정후 - App.vue]
<template>
<div>
<active-element
:topic-title="activeTopic && activeTopic.title"
:text="activeTopic && activeTopic.fullText"
></active-element>
<knowledge-base></knowledge-base>
</div>
</template>
<script>
export default {
data() {
return {
topics: [
{
id: 'basics',
title: 'The Basics',
description: 'Core Vue basics you have to know',
fullText:
'Vue is a great framework and it has a couple of key concepts: Data binding, events, components and reactivity - that should tell you something!',
},
{
id: 'components',
title: 'Components',
description:
'Components are a core concept for building Vue UIs and apps',
fullText:
'With components, you can split logic (and markup) into separate building blocks and then combine those building blocks (and re-use them) to build powerful user interfaces.',
},
],
activeTopic: null,
};
},
methods: {
activateTopic(topicId) {
this.activeTopic = this.topics.find((topic) => topic.id === topicId);
},
},
provide(){
return{
topics: this.topics,
selectTopic: this.activateTopic,
}
}
};
</script>
<style>
* {
box-sizing: border-box;
}
html {
font-family: sans-serif;
}
body {
margin: 0;
}
section {
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.26);
margin: 2rem auto;
max-width: 40rem;
padding: 1rem;
border-radius: 12px;
}
ul {
list-style: none;
margin: 0;
padding: 0;
display: flex;
justify-content: center;
}
li {
border-radius: 12px;
border: 1px solid #ccc;
padding: 1rem;
width: 15rem;
margin: 0 1rem;
display: flex;
flex-direction: column;
justify-content: space-between;
}
h2 {
margin: 0.75rem 0;
text-align: center;
}
button {
font: inherit;
border: 1px solid #c70053;
background-color: #c70053;
color: white;
padding: 0.75rem 2rem;
border-radius: 30px;
cursor: pointer;
}
button:hover,
button:active {
background-color: #e24d8b;
border-color: #e24d8b;
}
</style>
[수정후 KnowledgeBase.vue]
<template>
<section>
<h2>Select a Topic</h2>
<knowledge-grid ></knowledge-grid>
</section>
</template>
<script>
export default {
};
</script>
[수정후 KnowledgeGrid.vue]
<template>
<ul>
<knowledge-element
v-for="topic in topics"
:key="topic.id"
:id="topic.id"
:topic-name="topic.title"
:description="topic.description"
></knowledge-element>
</ul>
</template>
<script>
export default {
inject: ['topics'],
mounted(){
alert(this.topics);
}
};
</script>
[수정후 KnowledgeElement.vue]
<template>
<li>
<h3>{{ topicName }}</h3>
<p>{{ description }}</p>
<button @click="selectTopic(id)">Learn More</button>
</li>
</template>
<script>
export default {
inject: ['selectTopic'],
props: ['id', 'topicName', 'description'],
};
</script>
[수정후 ActiveElement.vue]
<template>
<section>
<h2>{{ topicTitle }}</h2>
<p>{{ text }}</p>
</section>
</template>
<script>
export default {
props: ['topicTitle', 'text'],
};
</script>
'데일리 공부 기록' 카테고리의 다른 글
hands on vue - scoped 스타일 적용 (0) | 2023.03.09 |
---|---|
hands on vue - component의 global, local 이해(연습예제 고민하고 풀기!) (0) | 2023.03.09 |
hands on vue - emit 연습문제 (@submit.prevent, emit, vue.component ) (0) | 2023.03.07 |
hands on vue - emit와 익숙해지는 연습문제(해답) (0) | 2023.03.06 |
hands on vue - emit와 익숙해지는 연습문제 (0) | 2023.03.06 |