Vue.js로 간단하게 이미지 업로드 기능 만들기!!

18064 단어 Vue.js

연설


saaqiita 안녕하세요!!!
오늘 기사가 올라온 목요일은 석흑정수의'목요일의full'이라고 할 건데, 올리는 건 초상화 업로드!!!여러분 사진 올렸어요????!!!!!!!!
Vue.js를 사용하여 이미지 업로드를 실현할 수 있는 기회가 몇 번 있기 때문에 그 견해를 가장 적게 요약합니다!시간이 없다고 핑계를 대고 싸구려 기사를 쓰지 마라!!!쓰려면 진지한 사람이 누구야???
오레다!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!

미리 준비하다


그럼 우선 귀찮으니까 프로젝트는 vue-cli로 쉽게 끝내세요.vue-cli를 설치하세요.
$ npm install -g @vue/cli
$ vue create sakura
cli에서 어떻게 설정하는지 물어볼 테니 이번에는 묵인하세요.
Vue CLI v4.1.1
? Please pick a preset:
❯ default (babel, eslint)
  Manually select features
프로젝트가 완료되면 바로 서버를 시작합니다!!!
$ cd sakura
$ npm run serve

정해진 거 나왔어!!!하지만 이미 이 녀석과 작별을 고했다.생성된 구성 요소를 삭제합니다.
$ rm src/components/HelloWorld.vue
이대로 가면 HelloWorld.vue 이 구성 요소가 없는 것처럼 욕을 먹을 테니 Upload.vue 이라는 구성 요소를 잠시 만들어봅시다!!!
그리고 부모 구성 요소로 App.vue도 만들어졌습니다 Upload.vue.
src/components/Upload.vue
<template>
  <div>
    アップロード!!!!!!!!!!
  </div>
</template>

<script>
export default {
  name: 'Upload'
}
</script>
src/App.vue
<template>
  <div id="app">
    <Upload />
  </div>
</template>

<script>
import Upload from './components/Upload.vue'

export default {
  name: 'app',
  components: {
    Upload
  }
}
</script>
그럼 여기 와서 화면의 상황을 봅시다.

떫다!!!!!
매우 은 사이트가 생겼기 때문에 적당히gitcommit를 해서 본론으로 하는 이미지 업로드 기능을 실현해 보세요!!

상위 어셈블리 준비


이번 구상에서 Upload.vue 구성 요소가 생성한 이미지 정보를base64 인코딩하여 문자열로 모구성 요소App.vue가 수신하여 이미지로 다시 표시합니다!!!!
그러므로 우리 먼저 부구성 요소를 실시합시다!!!GOGO!!
diff --git a/src/App.vue b/src/App.vue
index ca84756..e7a00be 100644
--- a/src/App.vue
+++ b/src/App.vue
@@ -1,6 +1,7 @@
 <template>
   <div id="app">
-    <Upload />
+    <upload v-model="picture" />
+    <img :src="picture" />
   </div>
 </template>

@@ -11,6 +12,11 @@ export default {
   name: 'app',
   components: {
     Upload
+  },
+  data() {
+    return {
+      picture: null
+    }
   }
 }
 </script>
겸사겸사 스타일 준비도 해보세요.그냥 기분 좋게
diff --git a/src/App.vue b/src/App.vue
index e7a00be..577250f 100644
--- a/src/App.vue
+++ b/src/App.vue
@@ -20,3 +20,21 @@ export default {
   }
 }
 </script>
+
+<style>
+* {
+  box-sizing: border-box;
+}
+
+html {
+  font-size: 62.5%;
+}
+
+body {
+  color: #2c2d30;
+  font-size: 1.6rem;
+  font-family: "Hiragino Kaku Gothic Pro", "ヒラギノ角ゴ Pro W3", "Meiryo",
+    "メイリオ", "Osaka", "MS PGothic", arial, helvetica, clean, sans-serif;
+  line-height: 1.5;
+}
+</style>
이렇게 하면 부모 구성 요소로 그림을 수신하고 표시할 수 있습니다!!!나 너무 흥분했어!!!

서브어셈블리 준비


다음으로 Upload.vue 최소한의 설치를 진행하세요.
diff --git a/src/components/Upload.vue b/src/components/Upload.vue
index 77a5175..659d3b5 100644
--- a/src/components/Upload.vue
+++ b/src/components/Upload.vue
@@ -1,11 +1,120 @@
 <template>
   <div>
-    アップロード!!!!!!!!!!
+    <label v-if="!value" class="upload-content-space user-photo default">
+      <input ref="file" class="file-button" type="file" @change="upload" />
+      アップロードする
+    </label>
+
+    <div v-if="value" class="uploaded">
+      <label class="upload-content-space user-photo">
+        <input ref="file" class="file-button" type="file" @change="upload" />
+        <img class="user-photo-image" :src="value" />
+      </label>
+    </div>
   </div>
 </template>

 <script>
 export default {
-  name: 'Upload'
+  name: 'Upload',
+  props: {
+    value: {
+      type: String,
+      default: null
+    }
+  },
+  data() {
+    return {
+      file: null
+    }
+  },
+  methods: {
+    async upload(event) {
+      const files = event.target.files || event.dataTransfer.files
+      const file = files[0]
+
+      if (this.checkFile(file)) {
+        const picture = await this.getBase64(file)
+        this.$emit('input', picture)
+      }
+    },
+    getBase64(file) {
+      return new Promise((resolve, reject) => {
+        const reader = new FileReader()
+        reader.readAsDataURL(file)
+        reader.onload = () => resolve(reader.result)
+        reader.onerror = error => reject(error)
+      })
+    },
+    checkFile(file) {
+      let result = true
+      const SIZE_LIMIT = 5000000 // 5MB
+      // キャンセルしたら処理中断
+      if (!file) {
+        result = false
+      }
+      // jpeg か png 関連ファイル以外は受付けない
+      if (file.type !== 'image/jpeg' && file.type !== 'image/png') {
+        result = false
+      }
+      // 上限サイズより大きければ受付けない
+      if (file.size > SIZE_LIMIT) {
+        result = false
+      }
+      return result
+    }
+  }
 }
 </script>
+
+<style scoped>
+.user-photo {
+  cursor: pointer;
+  outline: none;
+}
+
+.user-photo.default {
+  align-items: center;
+  background-color: #0074fb;
+  border: 1px solid #0051b0;
+  border-radius: 2px;
+  box-sizing: border-box;
+  display: inline-flex;
+  font-weight: 600;
+  justify-content: center;
+  letter-spacing: 0.3px;
+  color: #fff;
+  height: 4rem;
+  padding: 0 1.6rem;
+  max-width: 177px;
+}
+
+.user-photo.default:hover {
+  background-color: #4c9dfc;
+}
+
+.user-photo.default:active {
+  background-color: #0051b0;
+}
+
+.user-photo-image {
+  max-width: 85px;
+  display: block;
+}
+
+.user-photo-image:hover {
+  opacity: 0.8;
+}
+
+.file-button {
+  display: none;
+}
+
+.uploaded {
+  align-items: center;
+  display: flex;
+}
+</style>
어쨌든 여기서 최소한의 아래를 시도해 봤습니다.이거 반 됐죠?
  • 로컬 컴퓨터에서 이미지 읽기
  • 이미지의 축소 이미지 표시
  • 이미지의base64 인코딩
  • 부모 구성 요소에 인코딩 이미지 데이터 바인딩
  • 그럼 순서대로 설명해 주세요.
    업로드 버튼을 누르면change 이벤트uploadmethod가 주워집니다.
        async upload(event) {
          const files = event.target.files || event.dataTransfer.files
          const file = files[0]
    
          if (this.checkFile(file)) {
            const picture = await this.getBase64(file)
            this.$emit('input', picture)
          }
        },
    
    이벤트 정보에서 얻은 파일에 대한 정보를 얻은 후 이 파일 데이터를 checkFilemethod에 전달하고 파일 형식 등 규격에 문제가 있는지 확인합니다.
        checkFile(file) {
          let result = true
          const SIZE_LIMIT = 5000000 // 5MB
          // ローカルマシンからの読み込みをキャンセルしたら処理中断
          if (!file) {
            result = false
          }
          // jpeg か png 関連ファイル以外は受付けない
          if (file.type !== 'image/jpeg' && file.type !== 'image/png') {
            result = false
          }
          // 上限サイズより大きければ受付けない
          if (file.size > SIZE_LIMIT) {
            result = false
          }
          return result
        }
    
    문제가 없다고 판단되면 getBase64method에 해당하는 file 데이터를 다시 전달하고 FileReader의 실례 방법을 이용하여 인코딩한다.
        getBase64(file) {
          return new Promise((resolve, reject) => {
            const reader = new FileReader()
            reader.readAsDataURL(file)
            reader.onload = () => resolve(reader.result)
            reader.onerror = error => reject(error)
          })
        },
    
    이 인코딩 이미지 정보의 값을 상위 구성 요소 App.vue 로 되돌려줍니다.
    ※ 또한 이곳의 활동명은this.$emit('input', picture), inputv-modelv-bind:value의 문법당 때문이다.그러고 보니 프로스로 받았어요v-on:input.

    작은 것은 value 구성 요소에서 크기를 조절하는 스타일이고, 큰 것은 부모 구성 요소Upload.vue에 전달되는 정보를 읽는 사람이다.성공했어!!
    그럼 마지막으로 삭제 기능과 오류 메시지 표시 기능을 추가합시다!!
    diff --git a/src/components/Upload.vue b/src/components/Upload.vue
    index 36dcddb..59b0f4d 100644
    --- a/src/components/Upload.vue
    +++ b/src/components/Upload.vue
    @@ -10,7 +10,17 @@
             <input ref="file" class="file-button" type="file" @change="upload" />
             <img class="user-photo-image" :src="value" />
           </label>
    +
    +      <button type="button" class="delete-button" @click="deleteImage">
    +        削除する
    +      </button>
         </div>
    +
    +    <ul v-if="fileErrorMessages.length > 0" class="error-messages">
    +      <li v-for="(message, index) in fileErrorMessages" :key="index">
    +        {{ message }}
    +      </li>
    +    </ul>
       </div>
     </template>
    
    @@ -25,7 +35,8 @@ export default {
       },
       data() {
         return {
    -      file: null
    +      file: null,
    +      fileErrorMessages: []
         }
       },
       methods: {
    @@ -38,6 +49,10 @@ export default {
             this.$emit('input', picture)
           }
         },
    +    deleteImage() {
    +      this.$emit('input', null)
    +      this.$refs.file = null
    +    },
         getBase64(file) {
           return new Promise((resolve, reject) => {
             const reader = new FileReader()
    @@ -48,6 +63,7 @@ export default {
         },
         checkFile(file) {
           let result = true
    +      this.fileErrorMessages = []
           const SIZE_LIMIT = 5000000 // 5MB
           // キャンセルしたら処理中断
           if (!file) {
    @@ -55,10 +71,12 @@ export default {
           }
           // jpeg か png 関連ファイル以外は受付けない
           if (file.type !== 'image/jpeg' && file.type !== 'image/png') {
    +        this.fileErrorMessages.push('アップロードできるのは jpeg画像ファイル か png画像ファイルのみです。')
             result = false
           }
           // 上限サイズより大きければ受付けない
           if (file.size > SIZE_LIMIT) {
    +        this.fileErrorMessages.push('アップロードできるファイルサイズは5MBまでです。')
             result = false
           }
           return result
    @@ -114,4 +132,24 @@ export default {
       align-items: center;
       display: flex;
     }
    +
    +.delete-button {
    +  background-color: #fff;
    +  border: none;
    +  color: #0074fb;
    +  margin-left: 2rem;
    +  padding: 0;
    +}
    +
    +.delete-button:hover {
    +  text-decoration: underline;
    +}
    +
    +.error-messages {
    +  color: #cf0000;
    +  list-style: none;
    +  margin: 0.4rem 0 0 0;
    +  padding: 0 0.2rem;
    +  font-size: 1.6rem;
    +}
     </style>
    

    안녕, 신비한 음악 파일을 올리려다가 혼났어.삭제도 가능해서 편리해요.

    끝말


    saa 이미지 미리보기 간단하게 완성!!!!!
    원래는 aax로 이미지 파일을 백엔드에 업로드하여 표시하고 다운로드하려고 하였으나, 이번에는 간단하게base64로 화면 표시를 진행하였다.
    맞다 맞다 과일 하면 모니카의 계절이다!!!모두 메리 크리스마스!!!!!!!!!!!!!!

    좋은 웹페이지 즐겨찾기