vue.svg

【Vue 2】ドラッグ&ドロップで画像を読み込む

Vue 2

サンプル

ドラッグ&ドロップする場合は、別ウィンドウで表示してください。

解説

ドラッグ&ドロップ

<template>
  <div class="image-input">
    <div
      class="image-input__field"
      :class="{ over: isDragOver }"
      @dragover.prevent="onDrag('over')"
      @dragleave="onDrag('leave')"
      @drop.stop="onDrop"
    >
      <input type="file" title @change="onChange" />
      <p>画像をドラッグ&ドロップ <br />またはクリックでファイル選択</p>
    </div>
  </div>
</template>

ドラッグ&ドロップを実装するにあたり、使用するイベントはdragoverdragleavedropの 3 つです。 これらのイベントについては、こちらの記事を参考にしてください。

dragoverdragleaveは見た目を変更するのに使用しています。 以下のように大した処理はしていません。

onDrag(type) {
  this.isDragOver = type === "over";
},

dropでは、ドロップされたファイル情報を読み取ります。 ファイル情報は具体的に、イベントオブジェクトのdataTransferから取得します。

今回はドロップされたファイルが 1 つかつ画像の場合のみ読み取るようにしています。

onDrop(event) {
  this.isDragOver = false;
  const files = event.dataTransfer.files;
  if (files.length !== 1 || files[0].type.indexOf("image") !== 0) {
    return;
  }
  this.readImage(files[0]);
},

実装のポイントは、dragoverprevent修飾子を、dropstop修飾子を付けることです。

dragoverprevent修飾子を付けることで、デフォルトの動作を抑制します。 これがなければdropは機能しません。

dropstop修飾子を付与するのは、親へのイベントの伝搬を防ぐためです。 これがなければ親要素のdropイベントが発火し、エラーが出力されます。

ファイル選択

ファイルを選択するには以下のようにtype=fileinputを宣言します。

<input type="file" title @change="onChange" />

「ファイル選択」というボタンをクリックするとフォルダが開き、ファイルを選択するとchangeイベントが発火します。 changeでは、dropと同様にファイル情報を読み取る処理を行います。 ただし、ファイル情報はdataTransferではなくtargetから取得する点が異なります。

onChange(event) {
  const files = event.target.files;
  if (files.length !== 1 || files[0].type.indexOf("image") !== 0) {
    return;
  }
  this.readImage(files[0]);
},

ファイル読み込み

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参照)を用います。

FileReaderonloadは、ファイルの読み込みが成功した場合に発生するイベントになります。 ここではファイルの読み込み後にImage要素を作成するようにしています。

あとはreadAsDataURL()で対象のファイルを読み込みます。

画像の表示

img

シンプルに<img>を使用して画像を表示します。

<img :src="image.src" />

Canvas

以下のように Canvas を使用して表示することもできます。 Canvas についてはあまり詳しくないので、詳細は割愛します。

<template>
  <!-- -->
  <canvas id="canvas"></canvas>
  <!-- -->
</template>

<script>
//...
methods: {
  //...
  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);
  }
  //...
}
</script>