【Vue.js】ドラッグ&ドロップで画像を読み込み表示するまで

Web

サンプル

下のようなものを作っていきます。ドラッグ&ドロップによる読み込みに加えて、通常のファイル選択もクリックすればできるようにしてあります。

ファイルデータの読み込み部分をコンポーネント化しており、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を参考にしてください。

DragEvent
DragEvent インターフェイスは、ドラッグアンドドロップの対話を表す DOM イベントです。ユーザーはタッチ面でポインティングデバイス (マウスなど) を置くことによりドラッグを開始して、ポインタを新たな場所 (別の DOM 要素など) にドラッグします。アプリケーションは独自の方法で、ドラッグアンドドロップの操...

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を用いて読み込む必要があります。

FileReader
FileReader オブジェクトを使うと、ユーザーのコンピューター内にあるファイル (もしくはバッファ上の生データ) をウェブアプリケーションから非同期的に読み込むことが出来ます。読み込むファイルやデータは File ないし Blob オブジェクトとして指定します。
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要素を作成しています。

Image()
The Image() constructor creates a new HTMLImageElement instance. It is functionally equivalent to document.createElement('img').

これを参照することで画像の表示を行います。

画像の表示

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のおすすめ書籍はコチラ -

コメント

タイトルとURLをコピーしました