λ³Έλ¬Έ λ°”λ‘œκ°€κΈ°
[개발] Practice/Vue.js

[Vue.js] μ„œλ²„ 없이 μ—…λ‘œλ“œν•œ 이미지 닀루기

by Connecting-the-dots 2022. 4. 6.
728x90
λ°˜μ‘ν˜•

πŸ’‘ μ‹€μŠ΅ 포인트!


πŸ’œ 파일 μ—…λ‘œλ“œ μ‹œ μ½”λ“œ μ‹€ν–‰ν•˜κΈ°

  • Vue λŠ” μ›ΉλΈŒλΌμš°μ € λ‹€λ£¨λŠ” 것을 λ„μ™€μ£ΌλŠ” λ„κ΅¬μΌλΏμ΄λ―€λ‘œ, μ‹€μ§ˆμ μœΌλ‘œ μ›Ή κ°œλ°œμ„ 잘 ν•˜κΈ° μœ„ν•΄μ„œλŠ” Vue λ¬Έλ²•λΏλ§Œ μ•„λ‹ˆλΌ μ›ΉλΈŒλΌμš°μ €μ˜ κΈ°λŠ₯듀을 많이 μ•Œμ•„μ•Ό ν•œλ‹€.
  • μ˜ˆμ „μ—λŠ” μ‚¬μš©μžκ°€ μ—…λ‘œλ“œν•œ 이미지λ₯Ό μ„œλ²„λ‘œ λ³΄λ‚΄μ„œ μ €μž₯ν•˜κ³ , μ €μž₯ν•œ 이미지 URL 을 λ‹€μ‹œ μ‚¬μš©μžμ—κ²Œ 보낸 λ‹€μŒ <img src=""> 에 λ„£μ–΄μ„œ λ³΄μ—¬μ£ΌλŠ” λ“± 과정이 λ³΅μž‘ν•˜μ—¬ λ°”λ‘œ λΈŒλΌμš°μ €μ— λ°˜μ˜ν•˜μ—¬ λ³΄μ—¬μ£ΌλŠ” 게 μ–΄λ €μ› λ‹€.
  • ν•˜μ§€λ§Œ IE11 μ΄μƒμ—μ„œλŠ” λΈŒλΌμš°μ € λ‚΄μ—μ„œ 직접 이미지λ₯Ό μ‘°μž‘ν•˜λŠ” 것이 κ°€λŠ₯ν•΄μ‘ŒλŠ”λ° λŒ€ν‘œμ μœΌλ‘œ 두가지 방법이 μžˆλ‹€.
    • FileReader() λ₯Ό μ‚¬μš©ν•˜κΈ°
      : 이미지λ₯Ό κΈ€μžλ‘œ λ³€ν™˜ν•  수 있고, λ³€ν™˜λœ κΈ€μžλŠ” μ–΄λ”˜κ°€μ— μ €μž₯ν•˜κ±°λ‚˜ μ‚¬μš©ν•˜λŠ” 것이 κ°€λŠ₯ν•˜λ‹€.
    • URL.createObjectURL() 을 μ‚¬μš©ν•˜κΈ°
      : 이미지 URL 을 잠깐 생성해쀀닀. (단, μƒˆλ‘œκ³ μΉ¨ν•˜λ©΄ 사라진닀.)

πŸ’œ URL.createObjectURL() μ‚¬μš©ν•΄λ³΄κΈ°

// 전체 μ½”λ“œ 미리보기
// 전체 μ½”λ“œμ˜ λ‚΄μš©μ΄ κΈΈμ–΄ 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 v-if="step === 2">λ°œν–‰</li>
    </ul>
    <img src="./assets/logo.png" class="logo" />
  </div>

  <Container :posts="posts" :step="step" :imgUrl="imgUrl" />

  <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: "",
    };
  },
  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++;
    },
  },
  components: {
    Container: Container,
  },
};
</script>

<style>
</style>

 

<input @change="uploadImg" type="file" id="file" class="inputfile" />
  • "+" λ²„νŠΌμ„ λˆŒλŸ¬μ„œ νŒŒμΌμ„ μ„ νƒν•΄μ„œ <input /> 에 λ³€ν™”κ°€ λ°œμƒν•˜λ©΄ uploadImg λΌλŠ” ν•¨μˆ˜κ°€ μ‹€ν–‰λ˜κ²Œ ν•΄μ£Όμ—ˆλ‹€.

 

  methods: {
    uploadImg(e) {
      let file = e.target.files;
      let url = URL.createObjectURL(file[0]);
      this.imgUrl = url;
      this.step++;
    }
  }
  • 이제 μœ„μ˜ uploadImg ν•¨μˆ˜λ₯Ό methods 에 μž‘μ„±ν•΄μ£Όλ©΄ λœλ‹€.
  • 파일이 μ—…λ‘œλ“œν•  λ•Œ e.target.files λΌλŠ” μ½”λ“œλ₯Ό ν™œμš©ν•˜λ©΄ μ—…λ‘œλ“œν•œ νŒŒμΌλ“€μ˜ 리슀트λ₯Ό μ•Œ 수 있으며, λ‚˜μ˜ 경우 이λ₯Ό file μ΄λΌλŠ” λ³€μˆ˜μ— λ‹΄μ•„μ£Όμ—ˆλ‹€.
  • 파일 ν•˜λ‚˜λ§Œ μ˜¬λ €λ„ array μžλ£Œν˜•μœΌλ‘œ λ§Œλ“€μ–΄μ£Όλ―€λ‘œ μ—…λ‘œλ“œν•œ 파일이 ν•˜λ‚˜μΈ 경우 ν˜Ήμ€ 첫번째 파일만 μž„μ˜μ˜ url 이 ν•„μš”ν•œ 경우, μœ„μ™€ 같이 URL.createObjectURL(file[0]) ν˜•νƒœμ˜ μ½”λ“œλ₯Ό μž‘μ„±ν•˜λ©΄ μž„μ˜μ˜ url 이 μƒμ„±λœλ‹€.
  • 그리고 이 κ³Όμ •μ—μ„œ μƒμ„±λœ url 은 Container.vue μ—μ„œ μ‚¬μš©ν•΄μ•Ό ν•˜λ―€λ‘œ, data 보관함에 imgUrl μ΄λΌλŠ” ν•­λͺ©μ„ λ§Œλ“€μ–΄μ€€ 후에 uploadImg() μ—μ„œ μž„μ˜λ‘œ μƒμ„±λœ url 을 imgUrl 에 μ €μž₯ν•΄μ£Όμ—ˆλ‹€.
  • μœ„μ˜ μž‘μ—…μ΄ λλ‚˜λ©΄ 메인 νŽ˜μ΄μ§€(step : 0)에 κ·ΈλŒ€λ‘œ λ‚¨μ•„μžˆλŠ” 게 μ•„λ‹ˆλΌ ν•„ν„° 선택 νŽ˜μ΄μ§€(step: 1)둜 λ„˜μ–΄κ°€μ•Ό ν•˜λ―€λ‘œ step 값을 +1 ν•΄μ£Όμ—ˆλ‹€.
  • 이제 μƒμ„±λœ url 이 μ €μž₯된 imgUrl 을 imgUrl μ΄λΌλŠ” μ΄λ¦„μœΌλ‘œ props 문법을 톡해 Container.vue 둜 전솑해주면 Container.vue μ—μ„œ imgUrl 을 μ‚¬μš©ν•  수 있게 λœλ‹€.

πŸ’œ μƒμ„±λœ μž„μ‹œ URL λ°μ΄ν„°λ°”μΈλ”©ν•˜κΈ°

// 전체 μ½”λ“œ 미리보기
// 전체 μ½”λ“œμ˜ λ‚΄μš©μ΄ κΈΈμ–΄ 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">write!</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>
  • App.vue λ‘œλΆ€ν„° props λ¬Έλ²•μœΌλ‘œ 전달받은 imgUrl 을 props 에 등둝해쀀 λ‹€μŒ, <template></template> λ‚΄μ—μ„œ ν•„μš”ν•œ 뢀뢄에  style 의 background-image μ†μ„±μœΌλ‘œ λ°μ΄ν„°λ°”μΈλ”©ν•΄μ£Όμ—ˆλ‹€.

 

728x90
λ°˜μ‘ν˜•