もがき系プログラマの日常

もがき系エンジニアの勉強したこと、日常のこと、気になっている技術、備忘録などを紹介するブログです。

vueで画像 upload

はじめに

こんばんは。

今回はVueで画像のアップロードを試してみました。

参考にさせてもらったのはこちらです。

スタイルは前回同様 tailwindcss を使用しています。

本題

今回も、前回同様 vee-validateをかけ合わせた componentを使用しています。

<template>
  <div class="mb-4">
    <validation-provider
      v-slot="{ errors, validate }"
      :rules="internalValidateRule"
    >
      <label class="block text-sm font-bold mb-2">{{ label }}</label>

      <label
        class="upload-field inline-block cursor-pointer rounded text-white bg-blue-600 hover:bg-blue-800"
      >
        <input
          v-if="reset"
          type="file"
          @change="imageUpload($event, errors, validate)"
        />画像を選択
      </label>

      <div
        v-show="internalValue"
        class="max-w-sm h-64 rounded overflow-hidden shadow-lg mt-2"
      >
        <img class="w-full" :src="internalValue" />
      </div>
      <div
        v-show="internalValue"
        class="inline-block bg-red-200 hover:bg-red-400 rounded px-3 py-1 text-sm font-semibold text-gray-700 mr-2 mt-2 cursor-pointer"
        @click="remove"
      >
        close
      </div>
      <div class="text-red-500">
        {{ errors[0] }}
      </div>
    </validation-provider>
  </div>
</template>

<script>
export default {
  name: 'ImageUpload',
  props: {
    value: {
      type: String,
      default: ''
    },
    label: {
      type: String,
      default: 'テキスト'
    },
    validateRules: {
      type: String,
      default: null
    }
  },
  data() {
    return {
      reset: true,
      maxSize: 20 * 1024 ** 5,
      defaultValidateRules: 'image|ext:jpeg,jpg,png'
    }
  },
  computed: {
    internalValidateRule() {
      if (this.validateRules && this.validateRules.length !== null) {
        return `${this.validateRules}|${this.defaultValidateRules}`
      }
      return this.defaultValidateRules
    },
    internalValue: {
      get() {
        return this.value
      },
      set(newValue) {
        if (this.value !== newValue) {
          this.$emit('update:value', newValue)
        }
      }
    }
  },
  methods: {
    async imageUpload(e, errors, validate) {
      const result = await validate(e)
      if (!result.valid) {
        errors.push(result.errors[0])
        return
      }

      const files = e.target.files || e.dataTransfer.files

      const filesSize = files.length
        ? Array.from(files).reduce((previous, current) => (previous += current.size), 0)
        : 0

      if (filesSize > this.maxSize) {
        errors.push('アップロードできるファイルサイズは5Mまでです')
        return
      }

      this.createImage(files[0])
    },
    createImage(file) {
      const reader = new FileReader()
      reader.onload = e => {
        this.internalValue = e.target.result
      }
      reader.readAsDataURL(file)
    },
    remove() {
      this.internalValue = ''
      this.reset = false
      this.$nextTick(function() {
        this.reset = true
      })
    }
  }
}
</script>

<style scoped>
.upload-field {
  padding: 10px 30px;
}

input[type='file'] {
  display: none;
}
</style>

gyazo.com

ファイルサイズの制限、close後のfile.valueのリセットなど、ググりまくってコレに落ち着きました。 また、vee-validateで mimetypeの制限をかけたいときに @changeイベントが先に動いて、validateが動かないという現象があったので、changeイベント先のメソッド内で直接 validationを実行して、エラーを取るようにしました。

一旦コレで問題なく動いていますが、また変な動きが出てきた場合は修正するかもです。

終わりに

前回のdatepickerと違って、しっくり来るライブラリがなかったので、かなり探して今の形に落ち着きました。 実際ガッツリ使い始めると、また不具合出てくるかもしれませんが、、、

画像アップロードならこういうライブラリおすすめだよ!みたいなのがあったらぜひ教えてほしいです!