サンプル
下のようなものを作っていきます。ドラッグ&ドロップによる読み込みに加えて、通常のファイル選択もクリックすればできるようにしてあります。
ファイルデータの読み込み部分をコンポーネント化しており、v-modelで相互に画像データを参照できるようにしています。
画像の読み込み
ドラッグ&ドロップ
<div class="image-input__field" :class="{'over': isDragOver}" @dragover.prevent="onDrag('over')" @dragleave="onDrag('leave')" @drop.stop="onDrop" > <!-- 略 --> </div>
今回、ドラッグ&ドロップを実装する上で使用しているイベントは、「dragover」、「dragleave」、「drop」の3つです。とはいうものの、正直「dragover」と「dragleave」はドラッグされたときのデザインを変更するためだけに使っているのでおまけに過ぎません。
ドラッグ関連のイベントについては説明しませんのでMDNを参考にしてください。
1つ注意する点としては、今回のようにファイルをドラッグ&ドロップする場合は、必ず「dragover」でpreventDefault()を宣言(prevent修飾子を設定)してください。これが無いとブラウザ側の通常動作としてファイルのプレビューが表示されてしまいます。(おまけといいつつ重要でしたね…。)
次に「drop」についてです。「drop」ではdataTransferから実際にドロップしたファイル情報を参照します。
今回の実装では、ファイル数は1、ファイルの種類は画像に限定したいので、それ以外のものは読み込まないように制御します。
onDrop(event) { const files = event.dataTransfer.files if (files.length !== 1 || files[0].type.indexOf('image') !== 0) { return } //TODO ファイルの読み込み処理 }
また「drop」では必ずstopPropagation()を宣言(stop修飾子を設定)してください。コンソールを見ればわかるのですが、これが無いとエラーが表示されます。これは、親要素にイベントが伝搬してしまい、親にはそんなイベントないのに実行すんな(・´з`・)となっています。
ファイル選択
ついでなので通常のファイル選択の方法についても軽く説明しておきます。ファイル選択は以下のようにtypeがfileのinputタグを宣言します。
<input type="file" title @change="onChange">
ファイル選択というボタンが表示されるのでクリックするとフォルダが開き、ファイルを選択すると「change」イベントが発生します。
「change」では、先程の「drop」と同様の処理を定義します。1つ違う点は、ファイル情報はtargetから参照します。
onChange(event) { const files = event.target.files //あとは同じ }
あとはいい具合にCSSで見えないようにすればOKです。ちなみにtitle属性を付与しているのは、そのままだとデフォルトのツールチップが表示されてしまうのが嫌だったからです。
.image-input__field > input { position: absolute; top: 0; left: 0; opacity: 0; width: 100%; height: 100%; }
ファイルの読み込み
上記で参照しているファイル情報を使用するにはFileReaderを用いて読み込む必要があります。
readImage(file) { let reader = new FileReader(); reader.onload = this.loadImage; reader.readAsDataURL(file); }, loadImage(e) { let image = new Image(); image.src = e.target.result; this.image = image; }
FileReaderのonloadは、ファイルの読み込みが成功した場合に発生するイベントになります。今回の場合は、ファイル読み込み後にImage要素を作成しています。
これを参照することで画像の表示を行います。
画像の表示
imgタグ
最もシンプルな画像の表示方法はimgタグですよね。もはや説明の必要はないかと思います。
<img :src="image.src">
Canvas
次にCanvasによる表示ですが、私はCanvasについて詳しくないため細かい説明はできません。単純に今回読み込んだ画像をそのまま表示したい場合は次の処理を実行します。
draw() { let canvas = document.getElementById("canvas"); let context = canvas.getContext("2d"); canvas.width = this.image.width; canvas.height = this.image.height; context.drawImage(this.image, 0, 0); }
画像処理とかやりたい場合はCanvasで読み込む必要があるようですね。
- Vue.jsのおすすめ書籍はコチラ -
コメント