728x90
λ°μν
π‘ μ€μ΅ ν¬μΈνΈ!
- μ΄μ μ νν° μ ννλ©΄ μ μ©μ΄ λκ² νλ κΈ°λ₯μ κΉλΉ‘νκ³ λ§λ€μ§ μμλ€κ³ νλλ° λ§μΉ¨... μ€λ 곡λΆν΄μ μ μ©κΉμ§ ν΄λ³΄μλ€.
- μ²μ κΈ°λ₯ λ§λ€κ³ μ¬λ¬λ² μ€νν΄λ³΄λ, νν° μ ν νμ΄μ§μμ μμ§ νν°λ₯Ό μ ννμ§λ μμλλ° μ΄μ μ μ ννλ νν°κ° κΈ°λ³ΈμΌλ‘ μ νλ κ²μ λ³΄κ³ μ½λλ₯Ό μΆκ°λ‘ μμ ν΄μ£Όμλ€.
- μ΄λ²μλ μΊ‘μ²νλ €κ³ μ¬λ¬λ² μ€νν΄λ³΄λ, νν°κ° μ νλ μνμμ νν° μ ν νμ΄μ§λ κΈ μμ± νμ΄μ§μμ "Cancel" λ²νΌμ λλ¬λ λ€μλ² μ΄λ―Έμ§ μ λ‘λν λ νν°κ° μ νλμ΄ μμ΄ μ½λλ₯Ό μΆκ° μμ ν΄μ£Όμλ€.
π mitt λΌμ΄λΈλ¬λ¦¬ μ¬μ©νκΈ°
- κ°λ λ©λ¦¬ λ¨μ΄μ Έμλ Component λ‘ λ°μ΄ν° μ μ‘μ ν΄μΌ ν κ²½μ°κ° μκΈ΄λ€.
- μλ₯Ό λ€μ΄, λμ κ²½μ° App.vue > Container.vue > FilterBox.vue μμΌλ‘ Component ν¬ν¨κ΄κ³κ° μμ λ FilterBox.vue μμ App.vue λ‘μ λ°μ΄ν° μ μ‘μ΄ νμνλ€.
- μ΄λ° μν©μμ custom event λ‘ λ°μ΄ν° μ μ‘μ ν΄μ£ΌκΈ°μλ 2λ²μ λ°μ΄ν° μ μ‘ κ³Όμ (FilterBox -> Container, Container -> App)μ κ±°μ³μΌ νλ―λ‘ μ½λκ° κΈΈμ΄μ§κ³ 볡μ‘ν΄μ§λ€.
- κ·Έλ¬λ―λ‘, mitt λΌλ μΈλΆ λΌμ΄λΈλ¬λ¦¬λ₯Ό μ¬μ©νλ©΄ λ³΄λ€ μ½κ² λ°μ΄ν° μ μ‘μ΄ κ°λ₯νλ€.
(Vue 2 λ²μ μμλ EventBus λΌλ κ²μ μ¬μ©νλ©΄ λμ§λ§ Vue 3 μμλ μ¬μ©μ΄ μμ§ λΆκ°νλ―λ‘ μΈλΆ λΌμ΄λΈλ¬λ¦¬λ₯Ό μ€μΉνλ κ²!)
π€ mitt μ€μΉνκΈ°
// npm μ μ΄μ©νλ κ²½μ°
npm install mitt
// yarn μ μ΄μ©νλ κ²½μ°
yarn add mitt
- ν°λ―Έλμ μ λ μ½λ μ€ νλλ₯Ό μ λ ₯νμ¬ mitt λΌμ΄λΈλ¬λ¦¬λ₯Ό μ€μΉνλ©΄ λλ€.
π€ mitt μ ν νκΈ°
import { createApp } from 'vue'
import App from './App.vue'
// mitt λΌμ΄λΈλ¬λ¦¬ μ
ν
import mitt from 'mitt'
let emitter = mitt();
let app = createApp(App);
app.config.globalProperties.emitter = emitter;
app.mount('#app')
- mitt μ ν μ μμ κ°μ΄ main.js νμΌμ μ½λλ₯Ό μΆκ° λ° μμ ν΄μ£Όλ©΄ λλ€.
- μ°Έκ³ λ‘ app.config.globalProperties λ λͺ¨λ Component μμ μ¬μ©ν μ μλ λ³μλ₯Ό λ±λ‘ν μ μκ² λμμ£Όλ μΌμ’ μ object μλ£μΈλ°, μ½κ² κΈλ‘λ² λ³μ 보κ΄ν¨μ΄λΌκ³ μκ°νλ©΄ λλ€.
- μ΄λ°μμΌλ‘ μμ£Ό μ°λ axios κ°μ κ²λ 보κ΄νλ©΄, κ° vue νμΌμμ axios λ₯Ό import ν΄μ€μ§ μλλΌλ axios λ₯Ό μ¬μ©ν μ μμΌλ―λ‘ νΈλ¦¬νλ€.
(λ€λ§, κΈ°μ‘΄μ axios.get κ³Ό κ°μ΄ μ½λλ₯Ό μμ±νλ€λ©΄, μ΄ λ°©μμ μ¬μ©ν λμλ this.axios.get κ³Ό κ°μ΄ μ½λλ₯Ό μμ±ν΄μ£Όμ΄μΌ νλ€.)
π€ mitt μ¬μ©νκΈ°
this.emitter.emit('μ μ‘ν _λ_μ¬μ©ν _μ΄λ¦', 'μ μ‘ν _λ°μ΄ν°')
- λ°μ΄ν°λ₯Ό μ μ‘νκ³ μ νλ κ³³μμ μμ κ°μ΄ μ½λλ₯Ό μμ±νλ©΄ μ μ‘μ΄ κ°λ₯νλ€.
this.emitter.on('μ μ‘ν _λ_μ¬μ©ν_μ΄λ¦', (data)=>{
// λ°μ΄ν° μμ νμ λ μ€νν μ½λ μμ±
// μ μ‘λ°μ λ°μ΄ν°λ μνλ μ΄λ¦μ νλΌλ―Έν°λ‘ λ°μ μΆλ ₯ν΄λ³΄λ©΄ λλ€.
})
- μ΄μ λ°μ΄ν°λ₯Ό μμ νκ³ μ νλ κ³³μμ μμ κ°μ΄ μ½λλ₯Ό μμ±νλ©΄ μμ μ΄ κ°λ₯νλ€.
- μΌλ°μ μΌλ‘ μμ νλ μ½λλ mounted() μμ μμ±νλ€.
π νν° μ μ© νμ΄μ§μμ μ νν νν°λ₯Ό μ λ‘λν μ΄λ―Έμ§μ λ°νν ν¬μ€νΈ μ΄λ―Έμ§μ μ μ©νκΈ°
- νν° μ μ© νμ΄μ§μμ μ¬μ©μκ° νλ¨μ 미리 νν°κ° μ μ©λμ΄ λ³΄μ¬μ§λ μμ μ΄λ―Έμ§λ€(보λΌμ νμ) μ€ νλλ₯Ό ν΄λ¦νλ©΄ μλ¨μ μ΄λ―Έμ§(λΉ¨κ°μ νμ)μ μ¬μ©μκ° μ νν νν°κ° μ μ©λ μ μμ΄μΌ νλ€.
- λν λ€μ νμ΄μ§μΈ κΈ μμ± νμ΄μ§μ μ΄λ―Έμ§μλ, "λ°ν" λ²νΌμ λλ₯Έ ν μλ‘ μ λ‘λλλ ν¬μ€νΈμ μ΄λ―Έμ§μλ νν°κ° λΉμ°ν μ μ©λμ΄ μμ΄μΌ νλ€.
π€ FilterBox.vue μμ App.vue λ‘ μ νν νν°λͺ μ μ‘νκΈ°
// μ 체 μ½λ 미리보기
// μ 체 μ½λμ λ΄μ©μ΄ κΈΈμ΄ css λΆλΆμ μ μΈνλ€.
<template>
<div class="item" @click="fire">
<div class="slot">
<slot></slot>
</div>
<div
class="filter-item"
:class="filter"
:style="`background-image: url(${imgUrl})`"
></div>
</div>
</template>
<script>
export default {
name: "FilterBox",
data() {
return {};
},
props: {
imgUrl: String,
filter: String,
},
methods: {
fire() {
this.emitter.emit("filterName", this.filter);
},
},
};
</script>
<style>
</style>
- κ·Έλμ FilterBox.vue μμ item μ΄λΌλ class λ₯Ό κ°μ§ <div> μμμ ν΄λ¦νλ©΄, μ΄ μμμ μ μ©λμ΄μλ filter μ΄λ¦μ΄ App.vue λ‘ μ μ‘λλλ‘ ν΄μ£Όμλ€.
- μ΄ λ, νκ·Έ μ체μ μ½λλ₯Ό μμ±νκΈ°μλ λ΄μ©μ΄ κΈΈκΈ° λλ¬Έμ methods μ fire() ν¨μλ₯Ό λ°λ‘ λ§λ€μ΄μ @click μμ±μΌλ‘ λ£μ΄μ£Όμλ€.
- fire() ν¨μμ μ½λλ₯Ό ν΄μνμλ©΄ μ¬μ©μκ° ν΄λ¦ν filter-item μ΄λΌλ class λ₯Ό κ°μ§ <div> μ λ°μ΄ν°λ°μΈλ©λ class μΈ filter λ₯Ό filterName μ΄λΌλ μ΄λ¦μΌλ‘ λ°μ΄ν° μ μ‘ν΄λ¬λΌλ κ²μ΄λ€.
(data 보κ΄ν¨μ νλͺ©μ΄λ props μ νλͺ©μ methods μμ μ¬μ©ν λλ κΌ this λ₯Ό λΆμ¬μ£Όμ΄μΌ νλ€.)
π€ App.vue μμ FilterBox.vue λ‘λΆν° μ μ‘λ°μ λ°μ΄ν° μμ νκΈ°
// μ 체 μ½λ 미리보기
// μ 체 μ½λμ λ΄μ©μ΄ κΈΈμ΄ css λΆλΆμ μ μΈνλ€.
<template>
<div class="header">
<ul class="header-button-left">
<li v-if="step === 1 || step === 2" @click="step = 0; filter = ''">Cancel</li>
</ul>
<ul class="header-button-right">
<li @click="step++" v-if="step === 1">Next</li>
<li @click="publish" v-if="step === 2">λ°ν</li>
</ul>
<img src="./assets/logo.png" class="logo" />
</div>
<Container
:posts="posts"
:step="step"
:imgUrl="imgUrl"
:filter="filter"
@content="content = $event"
/>
<button class="btn" @click="more" v-if="step === 0">λ보기</button>
<div class="footer" v-if="step === 0">
<ul class="footer-button-plus">
<input @change="uploadImg" type="file" id="file" class="inputfile" />
<label for="file" class="input-plus">+</label>
</ul>
</div>
</template>
<script>
import Container from "./components/Container.vue";
import posts from "./assets/posts";
import axios from "axios";
export default {
name: "App",
data() {
return {
posts: posts,
moreCnt: 0,
step: 0,
imgUrl: "",
content: "",
filter: "",
};
},
methods: {
more() {
axios
.get(`https://codingapple1.github.io/vue/more${this.moreCnt}.json`)
.then((result) => {
this.posts.push(result.data);
this.moreCnt++;
})
.catch(() => {
console.log("GET μμ²μ μ€ν¨νμ΅λλ€.");
});
},
uploadImg(e) {
let file = e.target.files;
let url = URL.createObjectURL(file[0]);
this.imgUrl = url;
this.step++;
},
publish() {
let myPost = {
name: "Bak Seoyun",
userImage: "https://placeimg.com/100/100/arch",
postImage: this.imgUrl,
likes: 28,
date: "Jun 1",
liked: false,
content: this.content,
filter: this.filter,
};
this.posts.unshift(myPost);
this.step = 0;
this.filter = "";
},
},
components: {
Container: Container,
},
mounted() {
this.emitter.on("filterName", (a) => {
this.filter = a;
});
},
};
</script>
<style>
</style>
- App.vue μ mounted() μμ FilterBox.vue μμ μ μ‘ν λ°μ΄ν°λ₯Ό μμ κ°μ΄ μ½λλ₯Ό μμ±νμ¬ μμ ν΄μ£Όμλ€.
- μ½λλ₯Ό ν΄μνμλ©΄ filterName μ΄λΌλ μ΄λ¦μΌλ‘ λ°μμ¨ λ°μ΄ν°λ₯Ό App.vue μ filter μ μ μ©ν΄λ¬λΌλ κ²μ΄λ€.
- κ·Έλ¦¬κ³ μ΄λ κ² μ μ©λ filter λ₯Ό publish() ν¨μμ filter νλͺ©μ μ μ©ν΄μ£Όλ©΄, fiilter νλͺ©μ μ¬μ©μκ° μ νν νν° μ΄λ¦μ΄ μμ±λ μ±λ‘ ν¬μ€νΈκ° λ°νλλ€.
(ν·κ°λ¦¬μ§ λ§μμΌ ν κ²μ μ¬κΈ°μ μ μ©νλ€κ³ λ°νλ ν¬μ€νΈ μ΄λ―Έμ§μ filter κ° μ μ©λλ κ²μ μλκ³ , μ΄ μμ μ ν΄λμ΄μΌ Post.vue μμ λ°λ³΅λ¬Έμ λ λ post μ class μ μμ±λ filter λ₯Ό μΆκ°ν μ μλ€.) - κ·Έλ¦¬κ³ publish() ν¨μ λ§μ§λ§μ this.filter ="" λΌλ μ½λλ₯Ό μΆκ°νμ¬ λ°νλ μ΄νμλ μ νλ filter κ° μλλ‘ μ΄κΈ°νν΄μ£Όμλ€.
(μ΄ μ½λλ₯Ό μμ±νμ§ μμΌλ©΄, κ·Έ λ€μλ²μ μ΄λ―Έμ§λ₯Ό μ λ‘λν λ μμ§ μ λ‘λν μ΄λ―Έμ§μ νν°λ₯Ό μ ννμ§λ μμλλ° μ΄μ μ μ ννλ νν°κ° μ μ©λμ΄ μλ κ²μ λ°κ²¬νκ² λλ€.) - νν°κ° μ νλ μνμμ "Cancel" λ²νΌμ λλ₯Έ λ€μ, λ€μ μ΄λ―Έμ§λ₯Ό μ λ‘λνλ €κ³ νλ©΄ κ·Έ μ μ μ ννλ νν°κ° μ μ©λμ΄ μκΈΈλ μ΄ κ²½μ°μλ μ νλ filter κ° μλλ‘ μ΄κΈ°ννλ μ½λλ₯Ό μΆκ°ν΄μ£Όμλ€.
π€ App.vue μμ Container.vue λ‘ filter μ μ‘νμ¬ μ΄λ―Έμ§μ νν° μ μ©νκΈ°
// μ 체 μ½λ 미리보기
// μ 체 μ½λμ λ΄μ©μ΄ κΈΈμ΄ css λΆλΆμ μ μΈνλ€.
<template>
<div>
<div v-if="step === 0">
<Post :post="post" v-for="(post, i) in posts" :key="i" />
</div>
<!-- νν°μ ννμ΄μ§ -->
<div v-if="step === 1">
<div
class="upload-image"
:class="filter"
:style="{ backgroundImage: `url(${imgUrl})` }"
></div>
<div class="filters">
<FilterBox
:filter="filter"
:imgUrl="imgUrl"
v-for="(filter, i) in filters"
:key="i"
>{{ filter }}</FilterBox
>
</div>
</div>
<!-- κΈμμ±νμ΄μ§ -->
<div v-if="step === 2">
<div
class="upload-image"
:class="filter"
:style="{ backgroundImage: `url(${imgUrl})` }"
></div>
<div class="write">
<textarea
class="write-box"
@input="$emit('content', $event.target.value)"
placeholder="λ΄μ©μ μ
λ ₯νμΈμ!"
></textarea>
</div>
</div>
</div>
</template>
<script>
import Post from "./Post.vue";
import FilterBox from "./FilterBox.vue";
export default {
name: "Container",
data() {
return {
filters: [
"aden",
"_1977",
"brannan",
"brooklyn",
"clarendon",
"earlybird",
"gingham",
"hudson",
"inkwell",
"kelvin",
"lark",
"lofi",
"maven",
"mayfair",
"moon",
"nashville",
"perpetua",
"reyes",
"rise",
"slumber",
"stinson",
"toaster",
"valencia",
"walden",
"willow",
"xpro2",
],
};
},
components: {
Post,
FilterBox,
},
props: {
posts: Array,
step: Number,
imgUrl: String,
filter: String,
},
};
</script>
<style>
</style>
- νν° μ ν νμ΄μ§μ κΈ μμ± νμ΄μ§μλ λΉμ°ν μ νν νν°κ° μ΄λ―Έμ§μ μ μ©μ΄ λμ΄μΌ νκΈ°μ μ½λ‘ ( : )μ μ¬μ©νμ¬ class μμ±μ filter λ₯Ό λ°μ΄ν°λ°μΈλ©νμ¬ λ£μ΄μ£Όμλ€.
π€ Post.vue λ₯Ό ν΅ν΄ κ° post μ μ΄λ―Έμ§μ filter μ μ©νκΈ°
// μ 체 μ½λ 미리보기
// μ 체 μ½λμ λ΄μ©μ΄ κΈΈμ΄ css λΆλΆμ μ μΈνλ€.
<template>
<div class="post">
<div class="post-header">
<div
class="profile"
:style="{ backgroundImage: `url(${post.userImage})` }"
></div>
<span class="profile-name">{{ post.name }}</span>
</div>
<div
class="post-body"
:class="post.filter"
:style="{
backgroundImage: `url(${post.postImage})`,
}"
></div>
<div class="post-content">
<p>{{ post.likes }} Likes</p>
<p>
<strong>{{ post.name }}</strong> {{ post.content }}
</p>
<p class="date">{{ post.date }}</p>
</div>
</div>
</template>
<script>
</style>
- postImage κ° μ μ©λλ post-body λΌλ class λ₯Ό κ°μ§ <div> μ class λ₯Ό νλ λ μΆκ°νμ¬ post.filter λ₯Ό λ°μ΄ν°λ°μΈλ©ν΄μ£Όμλ€.
- μ΄ μμ μ ν΅ν΄ μ΄μ κ° posts λ°μ΄ν°μ ν¬ν¨λ filter νλͺ©λ€μ΄ μ€μ λ‘ μ΄λ―Έμ§μ μ μ©μ΄ λλ€.
728x90
λ°μν
'[κ°λ°] Practice > Vue.js' μΉ΄ν κ³ λ¦¬μ λ€λ₯Έ κΈ
[Vue.js] Vuex2: μ’μμ & μ’μμ μ·¨μ & μ’μμ μ¬λΆ νμ κΈ°λ₯ λ§λ€κΈ° (0) | 2022.04.08 |
---|---|
[Vue.js] Vuex1: Vuex μ ν νκΈ° (0) | 2022.04.07 |
[Vue.js] props λμ slot μ¬μ©ν΄λ³΄κΈ° (0) | 2022.04.07 |
[Vue.js] μΈμ€νκ·Έλ¨ νν° κΈ°λ₯ λ§λ€κΈ° (0) | 2022.04.07 |
[Vue.js] κΈλ°ν κΈ°λ₯ λ§λ€κΈ° (0) | 2022.04.06 |