LoginSignup
4
6

More than 5 years have passed since last update.

[JavaScript] ファイルのドロップイベントをJavaScriptから発火させる

Posted at

問題

ファイルをドロップしたときに発火するイベントを、JavaScriptから発火させたい。
以下のような使い方ができる関数fireDropEventを作れればよいとしよう。

fireDropEvent(document.documentElement, [new File(["Hello."], "hello.txt")]);

各種APIのドキュメントを読んですぐに思いつくのは以下のような実装だろう。

function fireDropEvent(domElement, files) {
  const dataTransfer = new DataTransfer();
  // (ここに、dataTransfer に files を登録する何らかのコードを入れる)
  domElement.dispatchEvent(new DragEvent("drop", {dataTransfer}));
}

しかし、現状DataTransferにファイルを登録するAPIは存在しないので、上のような方式の実装は不可能である。
どうすればよいか。

対処法

ダックタイピングを使う。

function fireDropEvent(domElement, files) {
  // DataTransferの偽物を定義する
  class FakeDataTransfer {
    constructor(files) {
      this.dropEffect = "none";
      this.effectAllowed = "all";
      this.files = files;
      this.types = ["Files"];
    }
    addElement() {
      // do nothing
    }
    clearData() {
      // do nothing
    }
    getData() {
      return "";
    }
    setData() {
      // do nothing
    }
    setDragImage() {
      // do nothing
    }
  }

  // あとはFakeDataTransferを本物のDataTransferといかにして差し替えるかが問題だが、
  // 以下の実装は怒られてしまう
  // 
  // ダメな実装例1:
  // const event = new DragEvent("drop", {dataTransfer: new FakeDataTransfer(files)});
  // DragEventのコンストラクタはDataTransferのインスタンスしか受け付けないので不可
  // 
  // ダメな実装例2:
  // const event = new DragEvent("drop");
  // event.dataTransfer = new FakeDataTransfer(files);
  // dataTransferへの代入は不可

  // なので、ECMAScript 5のdefinePropertyという機能を使って上書きする
  const event = new DragEvent("drop");
  Object.defineProperty(event, "dataTransfer", {value: new FakeDataTransfer(files)});
  domElement.dispatchEvent(event);
}

参考リンク

Trigger 'drop' event while providing the file data

4
6
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
4
6