๋ณธ๋ฌธ ๋ฐ”๋กœ๊ฐ€๊ธฐ
[๊ฐœ๋ฐœ] Practice/Vue.js

[Vue.js] ๊ธ€๋ฐœํ–‰ ๊ธฐ๋Šฅ ๋งŒ๋“ค๊ธฐ

by Connecting-the-dots 2022. 4. 6.
728x90
๋ฐ˜์‘ํ˜•

๐Ÿ’ก ์‹ค์Šต ํฌ์ธํŠธ!


๐Ÿ’œ "๋ฐœํ–‰" ๋ฒ„ํŠผ ๋ˆ„๋ฅด๋ฉด ๊ธ€๋ฐœํ–‰๋˜๋Š” ๊ธฐ๋Šฅ ๋งŒ๋“ค๊ธฐ

// ์ „์ฒด ์ฝ”๋“œ ๋ฏธ๋ฆฌ๋ณด๊ธฐ
// ์ „์ฒด ์ฝ”๋“œ์˜ ๋‚ด์šฉ์ด ๊ธธ์–ด css ๋ถ€๋ถ„์€ ์ œ์™ธํ–ˆ๋‹ค.

<template>
  <div class="header">
    <ul class="header-button-left">
      <li v-if="step === 1 || step === 2" @click="step = 0">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"
    @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: "",
    };
  },
  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: "perpetua",
      };
      this.posts.unshift(myPost);
      this.step = 0;
    },
  },
  components: {
    Container: Container,
  },
};
</script>

<style>
</style>
  • "๋ฐœํ–‰" ๋ฒ„ํŠผ์„ ๋ˆ„๋ฅด๋ฉด ์‚ฌ์šฉ์ž๊ฐ€ ์—…๋กœ๋“œํ•œ ์ด๋ฏธ์ง€์™€ ์ž‘์„ฑํ•œ ๊ธ€์ด ๋ฉ”์ธํŽ˜์ด์ง€ ๋งจ ์œ„์˜ ํฌ์ŠคํŠธ๋กœ ๋– ์•ผ ํ•œ๋‹ค.
  • ์ฆ‰, "๋ฐœํ–‰" ๋ฒ„ํŠผ์„ ๋ˆŒ๋ €์„ ๋•Œ posts ๋ฐ์ดํ„ฐ์˜ ๋งจ ์•ž์— ์‚ฌ์šฉ์ž๊ฐ€ ์—…๋กœ๋“œํ•œ ์ด๋ฏธ์ง€์™€ ์ž‘์„ฑํ•œ ๊ธ€์ด object ํ˜•์‹์œผ๋กœ ๋“ค์–ด๊ฐ€์•ผ ํ•˜๋Š” ๊ฒƒ์ด๋‹ค.
  • ๊ทธ๋Ÿฌ๋ฉด ์—…๋ฐ์ดํŠธ๋œ posts ๋ฐ์ดํ„ฐ๊ฐ€ ๋ฐ˜๋ณต๋ฌธ์„ ๋Œ๋ฉด์„œ ๊ฐ๊ฐ์˜ ๋ฐ์ดํ„ฐ๋ฅผ Post component ์— ๋ฐ์ดํ„ฐ๋ฐ”์ธ๋”ฉ๋˜์–ด ๋ฉ”์ธ ํŽ˜์ด์ง€์— ๋ณด์—ฌ์ง„๋‹ค.

 

<li @click="publish" v-if="step === 2">๋ฐœํ–‰</li>
  • ๋จผ์ €, "๋ฐœํ–‰" ๋ฒ„ํŠผ์„ ํด๋ฆญํ•˜๋ฉด publish() ๋ผ๋Š” ํ•จ์ˆ˜๊ฐ€ ๋™์ž‘ํ•˜๋„๋ก ํ•ด์ฃผ์—ˆ๋‹ค.

 

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: "perpetua",
  };
  this.posts.unshift(myPost);
  this.step = 0;
},
  • posts ๋ผ๋Š” ๋ฐ์ดํ„ฐ์— ์‚ฌ์šฉ์ž๊ฐ€ ์ž‘์„ฑํ•œ post ๋ฅผ ์ถ”๊ฐ€ํ•˜๋ ค๋ฉด, ์œ„์™€ ๊ฐ™์ด ๊ธฐ์กด์˜ posts ๋‚ด์˜ object ๋ฐ์ดํ„ฐ์™€ ๋˜‘๊ฐ™์€ ํ˜•์‹์œผ๋กœ object ๋ฅผ ํ•˜๋‚˜ ๋งŒ๋“  ๋‹ค์Œ, posts ์— unshift() ํ•จ์ˆ˜๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์ถ”๊ฐ€ํ•ด์ฃผ๋ฉด ๋œ๋‹ค.
  • ์ด๋ฒˆ์— push() ๋Œ€์‹  unshift() ๋ฅผ ์‚ฌ์šฉํ•œ ์ด์œ ๋Š” ๋ธŒ๋ผ์šฐ์ €์—์„œ ๋ณด์—ฌ์ง€๋Š” ํฌ์ŠคํŠธ๋“ค ์ค‘ ๋งจ ์œ„์— ์žˆ๋Š” ํฌ์ŠคํŠธ๊ฐ€ ์ƒˆ๋กœ ์ถ”๊ฐ€ํ•œ ํฌ์ŠคํŠธ์—ฌ์•ผ ํ•˜๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค.
  • ๊ทธ๋ฆฌ๊ณ  "๋ฐœํ–‰" ๋ฒ„ํŠผ์„ ํ†ตํ•ด ๋ฐœํ–‰์ด ๋˜๊ณ  ๋‚˜๋ฉด ๊ทธ๋Œ€๋กœ ๊ธ€์ž‘์„ฑ ํŽ˜์ด์ง€์— ๋จธ๋ฌด๋Š” ๊ฒŒ ์•„๋‹ˆ๋ผ ๋ฉ”์ธ ํŽ˜์ด์ง€๋กœ ๋Œ์•„์˜ค๋Š” ๊ฒƒ์ด ์ž์—ฐ์Šค๋Ÿฌ์šฐ๋ฏ€๋กœ step ์„ 0 ์œผ๋กœ ๋ฐ”๊พธ์–ด์ฃผ๋ฉด ๋œ๋‹ค.
  • ์—ฌ๊ธฐ์„œ ์—…๋กœ๋“œํ•œ ์ด๋ฏธ์ง€๋Š” imgUrl ์„ ๊ฐ€์ ธ์˜ค๋ฉด ๋˜๋ฏ€๋กœ ๋ฌธ์ œ๊ฐ€ ๋˜์ง€ ์•Š๋Š”๋ฐ, ์‚ฌ์šฉ์ž๊ฐ€ ์ž‘์„ฑํ•œ ๊ธ€ ๋‚ด์šฉ์€ ์–ด๋–ป๊ฒŒ ๊ฐ€์ ธ์˜ค๋ฉด ๋ ๊นŒ?
  • ๋ฐ”๋กœ data ๋ณด๊ด€ํ•จ์— content ๋ผ๋Š” ํ•ญ๋ชฉ์„ ๋งŒ๋“ค์–ด์„œ, ํ•˜์œ„ Component ์ธ Container.vue ์—์„œ <textarea/> ์— ์ž…๋ ฅ๋œ ๊ฐ’์„ custom event ๋กœ ๋ฐ›์•„์˜ค๋ฉด ๋œ๋‹ค.

 

// ์ „์ฒด ์ฝ”๋“œ ๋ฏธ๋ฆฌ๋ณด๊ธฐ
// ์ „์ฒด ์ฝ”๋“œ์˜ ๋‚ด์šฉ์ด ๊ธธ์–ด 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"
        :style="{ backgroundImage: `url(${imgUrl})` }"
      ></div>
      <div class="filters">
        <div class="filter-1"></div>
        <div class="filter-1"></div>
        <div class="filter-1"></div>
        <div class="filter-1"></div>
        <div class="filter-1"></div>
      </div>
    </div>

    <!-- ๊ธ€์ž‘์„ฑํŽ˜์ด์ง€ -->
    <div v-if="step === 2">
      <div
        class="upload-image"
        :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";
export default {
  name: "Container",
  data() {
    return {};
  },
  components: {
    Post: Post,
  },
  props: {
    posts: Array,
    step: Number,
    imgUrl: String,
  },
};
</script>

<style>
</style>
  • ์œ„ ์ฝ”๋“œ์™€ ๊ฐ™์ด ์‚ฌ์šฉ์ž๊ฐ€ <textarea /> ์— ์ž…๋ ฅํ•œ ๊ฐ’์ธ $event.target.value ๋ฅผ @input ์„ ํ†ตํ•ด content ๋ผ๋Š” ์ด๋ฆ„๊ณผ ํ•จ๊ป˜ App.vue ๋กœ ์ „์†กํ•ด์ฃผ์—ˆ๋‹ค.

 

  <Container
    :posts="posts"
    :step="step"
    :imgUrl="imgUrl"
    @content="content = $event"
  />
  • App.vue ์—๋Š” ์ด๋ฏธ data ๋ณด๊ด€ํ•จ์— content ๋ผ๋Š” ํ•ญ๋ชฉ์„ ๋งŒ๋“ค์–ด๋‘์—ˆ์œผ๋‹ˆ, ์œ„ ์ฝ”๋“œ์ฒ˜๋Ÿผ custom event ๋ฅผ @content ๋กœ ๋ฐ›์•„์„œ content ์— $event ๋ฅผ ์ €์žฅํ•ด์ฃผ์—ˆ๋‹ค.
  • ์ด์ œ <textarea /> ๊ฐ€ ์ˆ˜์ •๋  ๋•Œ๋งˆ๋‹ค content ์— ๋ฐ์ดํ„ฐ๊ฐ€ ์ €์žฅ๋˜๊ณ , "๋ฐœํ–‰" ๋ฒ„ํŠผ์„ ๋ˆ„๋ฅด๋ฉด ์ตœ์ข…์ ์œผ๋กœ ์ €์žฅ๋œ ๋ฐ์ดํ„ฐ๊ฐ€ publish() ๋‚ด์— this.content ์— ํ• ๋‹น๋˜๋Š” ๊ฒƒ์ด๋‹ค.

 

728x90
๋ฐ˜์‘ํ˜•