はじめに
こんばんは。
今回は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>
ファイルサイズの制限、close後のfile.valueのリセットなど、ググりまくってコレに落ち着きました。 また、vee-validateで mimetypeの制限をかけたいときに @changeイベントが先に動いて、validateが動かないという現象があったので、changeイベント先のメソッド内で直接 validationを実行して、エラーを取るようにしました。
一旦コレで問題なく動いていますが、また変な動きが出てきた場合は修正するかもです。
終わりに
前回のdatepickerと違って、しっくり来るライブラリがなかったので、かなり探して今の形に落ち着きました。 実際ガッツリ使い始めると、また不具合出てくるかもしれませんが、、、
画像アップロードならこういうライブラリおすすめだよ!みたいなのがあったらぜひ教えてほしいです!