2020/10/09

Vue.jsで見た目が綺麗なImage Pickerを作る

vuejsnuxtjs

概要

image-picker-min.png

こんな感じの、未選択画像をクリックすると画像をローカルから選択できて
選択後にアップロードなどに使えるコントロールをVue.jsを使って簡単に作ってみたいので、その内容のメモになります。

  • 画像エリアをクリックすると画像選択ができます
  • ローカルから画像をドロップして選択もできます

実装方法

マークアップ

htmlマークアップ部分は以下のような感じになります

ポイントとしては

  • 画像の表示用のURLが設定されている場合はimgタグを表示し、そうでない場合は、未設定のアイコンが表示されるようにします。
    • 以下の例では、vuetifyのコントロールを使っていますが、普通のhtmlタグ(v-imgの代わりにimgタグを、v-sheetやv-rowなどの代わりにdivタグ)を使っても動くはずです
  • また、input type="file"のコントロールを設定し、cssで隠れるようにします。(opacity: 0
<div
  class="image-picker-wrapper"
  :style="{ 'max-width': '320px' }"
>
  <v-img
    v-if="myImageUrl"
    max-width="320px"
    :src="myImageUrl"
  ></v-img>
  <v-sheet
    v-else
    color="grey lighten-3"
    width="320"
    height="164"
    tile
  >
    <v-row justify="center" align="center" class="fill-height">
      <v-icon size="82">mdi-image-off</v-icon>
    </v-row>
  </v-sheet>
  <input
    class="image-picker"
    type="file"
    accept="image/*"
    @change="myImageChanged"
  />
</div>
<style scoped lang="scss">
.image-picker-wrapper {
  position: relative;
  input.image-picker {
    position: absolute;
    top: 0;
    right: 0;
    bottom: 0;
    left: 0;
    display: block;
    width: 100%;
    height: 100%;
    cursor: pointer;
    opacity: 0;
  }
}
</style>

また、選択された後のデータの保存は以下の関数を定義しておきます。

これをすることで、画像をローカルPC上で選択した後に、imgタグで表示し、かつそのデータを myImageFile というフィールドに格納することができます。

export default {
  data() {
    return {
      myImageUrl: '',
      myImageFile: null,
	
    }
  },
  // もし画像ファイルをサイズを取得して最大byte数チェックなどをする場合には、以下を定義しておくと便利です
  computed: {
    myImageFileSize: {
      get() {
        this.myImageFile ? this.myImageFile.size : 0
      }
    },
  },
  methods: {
    myImageChanged(event) {
      let imageFile = null
      const files = event.target.files
      if (files.length > 0) {
        imageFile = files[0]
      }
      if (imageFile == null) {
        return
      }
      const self = this
      const reader = new FileReader()
      reader.onload = function() {
        const imageUrl = reader.result
        self.myImageFile = imageFile
        self.myImageUrl = imageUrl
      }
      reader.readAsDataURL(imageFile)
    }
  }
}

myImageFile に格納された画像ファイルのデータは以下のようにして、サーバーにアップすると良いでしょう。

アップロード時の処理

const formData = new FormData()
formData.append('my_image_file', this.myImageFile)
await this.$axios.$post('/your-server/file-upload-path', formData).then((data) => { /* 省略 */ }).catch((err) => { /* 省略 */ })

その他参考になる記事

以上です。