文系卒のWebエンジニアの成長と備忘録
エンジニア経験を生かして発信するメディアサイト

【JavaScript】ドラッグ&ドロップ機能を作成する方法

ドラッグ&ドロップ

JavaScriptを使用して、ドラッグ&ドロップ機能の作成方法を解説します。以下のようなやつですね。ユーザーからの写真やイラストやテキストファイルをサーバーに送信したりする際に使用するプラットフォームです。

JavaScriptと合わせて実装することで、ボタンでファイルを選択することだけではなく、ファイルをドラッグ&ドロップで選択出来るようにする事でユーザーが使い易くなり、少しでもサイトのユーザービリティが上がると思います。

ファイルを選択するためのデザインを作成しよう

HTMLは簡易的なもので用意しますが、ドラッグ&ドロップをすることを考慮し、ドラッグできる領域を明示的にした方がユーザー的に分かり易いので、当記事もそのように行います。

今回は、モバイル用のレイアウトは特に考慮していません。
下記2つのレイアウトを用意します。

  • ファイルを選択するためのボタン
  • ドラッグ&ドロップするための領域

<input type=”file”>でファイルを選択出来るようにしよう

ファイルを選択出来るようにするには<input type="file">を使用します。
ただ、デフォルトだと以下のようなデザインなので使い辛いですね。

そして実はHTMLの仕様でこの<input file="type">は直接CSSを当てて、デザインをボタン風にしたりする事ができません。しかし<label>タグと併用するとデザインを変更することが出来るようになります。

input fileのHTMLを整える

1

<input type="file" id="file_upload">

通常のinput fileでタグを用意して、idセレクタを設置します。この際のidセレクタの値はお好みで付けてOK

2

<label for="file_upload" class="select-file" id="js-select-file">
    ファイルを選択してください
    <input type="file" id="file_upload">
</label>

次に<label>タグを先ほど設置した<input type="file">の上の階層に設置します。
この時に先ほど設定したidセレクタの値と<label>タグに設定しているfor=””の値は一致させてください。

<label>に設定する文言は自由に変える事が出来ます。ここは通常<input type="file">を使用する際には変更することは出来ないのですが、このタグを使用することにより自由に変更が可能です。

ファイル選択ボタンのHTML全体像は以下

<label for="file_upload" class="select-file" id="js-select-file">
    ファイルを選択してください
    <input type="file" id="file_upload">
</label>

input fileのCSSを整える

1

input {
    display: none; 
}

デフォルトが邪魔なので隠してしまいましょう。まずは<input type="file">をdisplay: none;で消します。

1

.select-file {
    display: inline-block;
    margin: 40px auto;
    padding: 25px 40px;
    width: 400px;
    background-color: #1AA1FF;
    border-radius: 5px;
    color: #F7F7F7;
    cursor: pointer;
    font-weight: 700;
    z-index: 1; 
}

.select-file:hover {
    background-color: #136EB6; 
}

<label>タグに対して、デザインを当てていきます。このlabelタグ自体がボタンの役割を担っているのでボタンっぽいデザインに仕上げます。

cursor: pointer;などをつけるとボタンと明示出来ます。また、より分かり易いように、hover時に背景色なども変更します。

CSSの全体像は以下

input {
    display: none; 
}

.select-file {
    display: inline-block;
    margin: 40px auto;
    padding: 25px 40px;
    width: 400px;
    background-color: #1AA1FF;
    border-radius: 5px;
    color: #F7F7F7;
    cursor: pointer;
    font-weight: 700;
    z-index: 1; 
}

.select-file:hover {
    background-color: #136EB6; 
}

ドラッグ&ドロップするためのデザインを作成しよう

ファイル選択

まずはHTMLで、ファイルを選択するために必要な領域を作成します。
ここは通常のHTMLだけで細かいデザインはありません。

ドラッグ&ドロップするための領域を作成しよう

まずは大枠のHTMLだけ用意します。overlayと言われる要素を覆うための領域、その覆った要素に表示する文言、選択されたファイルを表示するためのタグを用意します。

ドラッグ&ドロップ領域のHTMLを作成する

1

<div class="container">
</div>

このHTMLは全ての大枠のためのタグです。ほぼ決まり文句のような感じです。

2

<div class="container">
    <div class="drop-zone" id="js-dropzone">
    </div>
</div>

先ほど作成した要素の中にドラッグ&ドロップ出来るための領域の要素を作成します。

後々記載しますが、JavaScriptの処理はここの要素を中心に書いていきます。

3

<div class="container">
    <div class="drop-zone" id="js-dropzone">
        <div class="overlay-area" id="js-overlay-area">
            <p class="no-active" id="js-overlay-text">ここにドラッグ&ドロップしてください。</p>
        </div>
        <p class="drop-zone-text">ファイルを選択するか、ドラッグ&ドロップしてください。</p>
    </div>
</div>

さらにドロップ領域の中に文言やoverlay要素を作成します。overlay-areaはファイルをドラッグした際に要素を覆い、どこにファイルをドロップするのか明示的にするために置いています。

4

<div class="container">
    <div class="drop-zone" id="js-dropzone">
        <div class="overlay-area" id="js-overlay-area">
            <p class="no-active" id="js-overlay-text">ここにドラッグ&ドロップしてください。</p>
        </div>
        <p class="drop-zone-text">ファイルを選択するか、ドラッグ&ドロップしてください。</p>
        <div class="selected-file no-active" id="js-selected-file">
        </div>
    </div>
</div>

selected-fileの要素を配置します。この要素は選択されたファイルを表示するための領域です。 input fileではデフォルトでこの機能がありますが、この機能を隠してしまっているため、自前で表示する必要があります。

ドラッグ&ドロップのためのHTMLの全体像

上記で書いたinput fileのHTMLと合体すると以下のようになります。

<div class="container">
    <div class="drop-zone" id="js-dropzone">
        <div class="overlay-area" id="js-overlay-area">
            <p class="no-active" id="js-overlay-text">ここにドラッグ&ドロップしてください。</p>
        </div>
        <p class="drop-zone-text">ファイルを選択するか、ドラッグ&ドロップしてください。</p>
        <label for="file_upload" class="select-file" id="js-select-file">
            ファイルを選択してください
            <input type="file" id="file_upload">
        </label>
        <div class="selected-file no-active" id="js-selected-file">
        </div>
    </div>
</div>

ドラッグ&ドロップ領域のCSSを作成する

1

.container {
    padding: 30px;
}

大枠の方にCSSを当てていきます。大枠なのでここら辺は結構適当です。

2

..drop-zone {
    position: relative;
    width: 1000px;
    height: 700px;
    margin: 0 auto;
    background-color: #eeeeee;
    font-size: 20px;
    font-weight: 700;
    text-align: center;    
}

ドロップするための領域にCSSを当てます。background-colorで背景色を少し変えることでドロップする領域を明示するとUI的に良いです。

また、position: relative;を入れていますが、これについては後々設定するoverlay要素のための準備です。

3

drop-zone-text {
    padding: 50px 0px;
}
ドロップするための領域に表示しておく文言のCSSです。ただの文言表示なので表示映えだけ整えます。

4

.overlay {
    position: absolute;
    width: 100%;
    height: 100%;
    background-color: rgba(0,0,0,.75);
    z-index: 100;
}

.overlay-text {
    display: block;
    position: absolute;
    top: 50%;
    left: 50%;
    color: #F7F7F7;
}

覆う要素であるoverlay要素のCSSを当てていきます。position: absolute;でドロップ領域を覆うようなデザインにしていきます。

特に特徴はないですがbackground-colorrgbaを使用すると背景色を指定(4番目の引数)しながら、透明度を指定できるので使用します。

※後々JavaScriptで書いていきますが、実際にファイルがドラッグされた時にこのoverlay要素が表示される仕組みになります。

5

.no-active {
    display: none;
}

最後に要素を隠すためのクラスを用意します。overlay要素などはデフォルトでは非表示にする必要があるためこのクラスを当てておきます。

ドラッグ&ドロップのためのCSSの全体像

上記全てのCSSを合わせると以下のような全体像になります。


.no-active {
   // 文字数の関係上、上記の⑤をご覧ください
}
.drop-zone {
   // 文字数の関係上、上記の②をご覧ください
}

.drop-zone-text {
    padding: 50px 0px;
}

.overlay {
    position: absolute;
    width: 100%;
    height: 100%;
    background-color: rgba(0,0,0,.75);
    opacity: 0.8;
    z-index: 100;
}

.overlay-text {
    display: block;
    position: absolute;
    top: 50%;
    left: 33%;
    color: #F7F7F7;
}

input {
    display: none;
}

.select-file {
    display: inline-block;
    margin: 40px auto;
    padding: 25px 40px;
    width: 400px;
    background-color: #1AA1FF;
    border-radius: 5px;
    color: #F7F7F7;
    cursor: pointer;
    font-weight: 700;
    z-index: 1;
}

.select-file::hover {
    background-color: #136EB6;
}

これで全てのHTMLとCSSが書き終わり、画面の雛形が作成出来ました。次に実際にJavaScriptを使用してファイルをドラッグ&ドロップ出来る動作にします。

JavaScriptでドラッグ&ドロップ機能を作成する

javascript

JavaScriptでファイルをドラッグ&ドロップする機能を作成するために必要なメソッドは4つ。以下のメソッドを使用して処理を書いていきます。

それぞれのイベントでどういった処理をするのか。
大まかですが基本的には以下のように行います。

dragenter
ドロップ領域にファイルが入った段階でoverlay要素を表示

dragleave
ドロップ領域からファイルが出た段階でoverlay要素を非表示

drop
ファイルがドロップされた段階でoverlay要素を非表示
ドロップされたファイルを表示する

dragover
これに関しては後ほど説明しますが、APIの使用上するものになります。
何か必要な処理を別段書くことになります。

この処理に基づいて実装すると以下のようになります。
まずは使用する要素を取得し、変数として宣言。

const dropzone = document.getElementById('js-dropzone');
const overlayText = document.getElementById('js-overlay-text');
const overlayArea = document.getElementById('js-overlay-area');
const fileInput = document.getElementById('file_upload');
const selectedFile = document.getElementById('js-selected-file');

dragenterの処理

overlay要素を表示します。

// ドロップ可能エリアに入った時
dropzone.addEventListener('dragenter', () => {
    overlayArea.classList.add('over-lay');
    overlayText.classList.add('over-lay-text');
    overlayText.classList.remove('no-active');
});

dragleaveの処理

overlay要素を非表示にし、デフォルトで表示されている画面のママに戻します。

// ドロップ可能エリアを出た時
overlayArea.addEventListener('dragleave', () => {
    overlayArea.classList.remove('over-lay');
    overlayText.classList.remove('over-lay-text');
    overlayText.classList.add('no-active');
});

dropの処理

ファイルがドロップされた際も基本はdropleaveの処理と同じです。
ですが、一番重要なドロップされたファイルを取得する処理も記載します。

// ファイルをドロップした時
overlayArea.addEventListener('drop', (e) => {
    e.preventDefault();
    var fileName = e.dataTransfer.files[0].name;
    selectedFile.innerText = fileName;
    selectedFile.classList.remove('no-active');
    overlayArea.classList.remove('over-lay');
    overlayText.classList.remove('over-lay-text');
    overlayText.classList.add('no-active');
});

補足:JavaScriptでファイルを取得する方法

JavaScriptでファイルを扱うには、Fileオブジェクトから中身を取得する必要があります。
Fileオブジェクトの中身は以下のようになっています。(Chromeのディベロッパーツールを使用してConsoleタブから確認することが出来ます。)

* FileList {0: File, length: 1}
* 0: File {name: “Index10.html”, lastModified: 1568851615530, lastModifiedDate: Thu Sep 19 2019 09:06:55 GMT+0900 (日本標準時), webkitRelativePath: “”, size: 2063, …}
length: 1
__proto__: FileList

読みやすいように整形すると以下のようになります。

* lastModified: 1568851615530
* lastModifiedDate: Thu Sep 19 2019 09:06:55 GMT+0900 (日本標準時) {}
* name: “Index10.html” これがファイル名
* size: 2063
* type: “text/html”
* webkitRelativePath: “”

上記でファイルの取得は出来るのですが、ここで注意点。
関数の部分に引数eを持っていますが、ここの処理ではこの引数が必須です。

この引数はイベントと言われるもので、ここのdropが発火した際にイベントオブジェクトが入ります。
詳しい説明は以下の記事で詳しく解説されているので参考にしてください。
≫ JavaScript初級者から中級者になろう

このイベントオブジェクトに実際にdropされた段階で起きたイベントの詳細が入っているので、そこからファイルを取得します。

また、APIの仕様上このイベントは止めないと流れていってしまい理想の挙動にはならないためe.preventDefault();で処理を止めないといけません。この仕様はdropdragoverの処理に適用する必要があります。

上記の理由からdragoverにも同様に処理を止めてあげる処理を書きます。

dragoverの処理

// ドロップ可能エリアにカーソルがある時
overlayArea.addEventListener('dragover', (e) => {
    e.preventDefault();
});

最後にボタンからファイルを選択しても、ドラッグ&ドロップから選択してもファイル名がきちんと表示されるようにファイル名を表示する仕組みを作成します。

fileInput.addEventListener('change', () => {
    var fileName = fileInput.files[0].name;
    selectedFile.classList.remove('no-active');
    selectedFile.innerText = fileName;
});

javaScriptの全体像

const dropzone = document.getElementById('js-dropzone');
const overlayText = document.getElementById('js-overlay-text');
const overlayArea = document.getElementById('js-overlay-area');
const fileInput = document.getElementById('file_upload');
const selectedFile = document.getElementById('js-selected-file');

// ドロップ可能エリアに入った時
dropzone.addEventListener('dragenter', () => {
    overlayArea.classList.add('overlay');
    overlayText.classList.add('overlay-text');
    overlayText.classList.remove('no-active');
});

// ドロップ可能エリアを出た時
overlayArea.addEventListener('dragleave', () => {
    overlayArea.classList.remove('overlay');
    overlayText.classList.remove('overlay-text');
    overlayText.classList.add('no-active');
});

// ドロップ可能エリアにカーソルがある時
overlayArea.addEventListener('dragover', (e) => {
    e.preventDefault();
});

// ファイルをドロップした時
overlayArea.addEventListener('drop', (e) => {
    e.preventDefault();
    var fileName = e.dataTransfer.files[0].name;
    selectedFile.innerText = fileName;
    selectedFile.classList.remove('no-active');
    overlayArea.classList.remove('overlay');
    overlayText.classList.remove('overlay-text');
    overlayText.classList.add('no-active');
});

fileInput.addEventListener('change', () => {
    var fileName = fileInput.files[0].name;
    selectedFile.classList.remove('no-active');
    selectedFile.innerText = fileName;
});

これで完成です!
PHPやRubyなどのプログラミング言語と合わせて作成すると、ファイルを実際にサーバーに送受信し、色々処理を施したりなどすることが出来ます。是非試してみてください。

人気記事【独学者おすすめ】プログラミング学習動画サービス3選

人気記事プログラミング実務未経験者が自社開発エンジニアになるための方法

人気記事エンジニアを目指しているなら使用すべき5つの転職サイト

\記事のシェアをお願いします!/