|||||||||||||||||||||

なんぶ電子

- 更新: 

Chrome ドラックドロップでファイル選択

Google Chromeでドロップでファイル選択

以前、スマホからPCへファイルを送信するWebアプリを作成しました。その際は、スマホ操作がメインでドラッグ&ドロップは考えていませんでしたが、PCでファイルを選択するにはドラッグ&ドロップでファイルが選択できると楽なので対応してみることにしました。

しかし、近年のGoogleChromeではデスクトップからブラウザへファイルをドラッグ&ドロップすると、新しいタブでファイルをオープンする挙動になっていると思います。

おそらくそのせいだと思いますが、筆者の環境(Windows11+Chrome106.0.5249.103)では、タグにondropイベントを設定してもイベントが反応しません。

同環境で回避策はその方法はないか考えてみました。

fileを指定したinput要素なら意図した反応をします

よく考えれば当たり前なのかもしれませんが、input type="file"の領域にドロップすると、ファイルはオープンされずに選択されます。また、この時ondropイベントも反応がありました。

sample1.html

<div style="width: 98%; border: 1px solid blue; padding: 10px" draggable="true" ondrop="console.log('dorp to div'); event.preventDefault();">
  <-- 本来ドラッグ&ドロップ用の領域 -->
</div>
ここへファイルをドロップすると、別タブでファイルが開く挙動(ブラウザの挙動)になってしまいます。

sample2.html

<input type="file" multiple ondrop="console.log('drop to input');" style="background-color: #ccf; display: block; width:98%; height: 3rem;"/>

typeがfileのinput要素の上ならドロップがファイル選択として機能し、ondropイベントも稼働します。(ボタンの上か青色の場所)

装飾

通常のinput type="file"の場合でも、そのデザイン性が微妙だという理由から、hiddenで隠しておいて、別の要素からclickイベントを起こすというような使い方がされます。

筆者はデザインが苦手なので見た目の微妙さは変わらないかもしれませんが、元のボタンや表示を隠す方法を考えてみました。

といっても、方法はinput type="file"を透明にして、その上に文字を出力するようにするだけです。

関連するセキュリティホールが発見されたりすると使えなくなったりするのかもしれませんが、執筆時点の環境では意図したように稼働させることができました。

sample3.html

<!DOCTYPE html>
<html lang="ja">
  <head>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>ドラック&ドロップのサンプル</title>
  </head>
  <body>
    <div style="width: 100%; height: 100px; border: 1px solid blue; padding: 0; position: relative;">
      <div style="position: absolute; text-align: center; width: 100%">
        <svg xmlns="http://www.w3.org/2000/svg" height="48" width="48">
          <path
            d="M22.6 37.9h3V27.85l4.1 4.1 2.1-2.1-7.8-7.6-7.7 7.7 2.1 2.1 4.2-4.2ZM11 44q-1.2 0-2.1-.9Q8 42.2 8 41V7q0-1.2.9-2.1Q9.8 4 11 4h18.05L40 14.95V41q0 1.2-.9 2.1-.9.9-2.1.9Zm16.55-27.7V7H11v34h26V16.3ZM11 7v9.3V7v34V7Z"
          />
        </svg>
        <br />
        <span>ここにファイルをドロップしてください</span>
        <ul style="list-style: none" id="file-list">
          <li>ファイルが選択されていません</li>
        </ul>
      </div>
      <input
        id="file"
        type="file"
        multiple
        ondrop="console.log('drop to input')"
        style="
          background-color: #ccf;
          display: block;
          width: 100%;
          height: 100%;
          opacity: 0;
        "
      />
    </div>
    <script>
      const file = document.getElementById("file");
      const list = document.getElementById("file-list");

      const adjustArea = () => {
        // ドラッグドロップの範囲の調整
        const last = list.querySelectorAll("li");

        if (0 < last.length) {
          const liBottom = last[last.length - 1].getBoundingClientRect().bottom;

          const fileRect = file.getBoundingClientRect();
          let targetHeight =
            fileRect.bottom - fileRect.top + (liBottom - fileRect.bottom) + 5;

          file.style.height = targetHeight + "px";
          file.parentNode.style.height = targetHeight + "px";
        }
      };

      window.addEventListener("load", () => {
        file.addEventListener("change", () => {
          // リストクリア
          while (list.hasChildNodes()) {
            list.removeChild(list.firstChild);
          }
          if (file.files.length == 0) {
            const li = document.createElement("li");
            li.textContent = "ファイルが選択されていません";
            list.appendChild(li);
          } else {
            for (const f of file.files) {
              const li = document.createElement("li");
              li.textContent = f.name;
              list.appendChild(li);
            }
          }

          // 高さの調整
          setTimeout(adjustArea(), 100);
        });

        // 高さの調整
        setTimeout(adjustArea(), 100);
      });
    </script>
  </body>
</html>

上記のコードを稼働させると次のようになります。


ここにファイルをドロップしてください
  • ファイルが選択されていません

筆者紹介


自分の写真
がーふぁ、とか、ふぃんてっく、とか世の中すっかりハイテクになってしまいました。プログラムのコーディングに触れることもある筆者ですが、自分の作業は硯と筆で文字をかいているみたいな古臭いものだと思っています。 今やこんな風にブログを書くことすらAIにとって代わられそうなほど技術は進んでいます。 生活やビジネスでPCを活用しようとするとき、そんな第一線の技術と比べてしまうとやる気が失せてしまいがちですが、おいしいお惣菜をネットで注文できる時代でも、手作りの味はすたれていません。 提示されたもの(アプリ)に自分を合わせるのでなく、自分の活動にあったアプリを作る。それがPC活用の基本なんじゃなかと思います。 そんな意見に同調していただける方向けにLinuxのDebianOSをはじめとした基本無料のアプリの使い方を紹介できたらなと考えています。

広告