JavaScript入門[HTML5編]複数のドロップ要素を扱う

  1. HOME
  2. JavaScript入門[HTML5編]
  3. 複数のドロップ要素を扱う

前のページでは複数のドラッグ要素にイベントを追加する方法を見ました。 このページでは複数のドロップ先にイベントを追加する方法について見ていきます。

複数のドロップ要素を扱うサンプルスクリプト

ドロップされるエリアを構成するのはdivタグです。 これをgetElementsByTagName()で取得することはできません。 このページには他にも沢山のdivタグが存在しているからです。

このような場合は、ドロップされるエリアのdivタグにだけ特有のクラス名を付け、 そのクラス名を持つ要素を取得するようにすればOKです。 以下の命令文で取得できます。

document.getElementsByClassName(クラス名)
目的のクラス名を持つ要素を、配列の形式で全て取得します。
document.querySelectorAll(".クラス名");
目的のクラス名を持つ要素を、配列の形式で全て取得します。
クラス名に限らず、CSSで記述するのと同じ方法で要素を指定できます。

以下のサンプルでは、ドロップされるエリアを2つ設けています。 このどちらかにアルファベット文字の画像をドラッグ&ドロップできるようにします。

<div id="dragarea">
<img src="img/a.png" widht="100" height="100" id="a" alt="">
<img src="img/b.png" widht="100" height="100" id="b" alt="">
<img src="img/c.png" widht="100" height="100" id="c" alt="">
<img src="img/d.png" widht="100" height="100" id="d" alt="">
</div>
<div class="dp" id="drop1"></div>
<div class="dp" id="drop2"></div>

<style type="text/css">
div#dragarea{ width:100%; height:100px; background-color:#80ffff }
div.dp{ width:50%; height:100px }
div#drop1{ background-color:#ffff80; float:left }
div#drop2{ margin-left:50%; background-color:#ff80ff;  }
div#drop2:after{ content:""; display:block; clear:left }
</style>

<script>
//imgタグ要素を全て取得する
var elm = document.getElementsByTagName("img");

//全imgタグにdragstartイベントを追加する
for ( var i=0 ; i < elm.length ; i++ )
{
  elm[i].addEventListener("dragstart", function(evt){
    evt.dataTransfer.setData("text/plain",evt.target.id);
    evt.stopPropagation();
  },false);
}

//クラス名「dp」を持つdivタグを全て取得する
var droparea = document.querySelectorAll("div.dp");

//全てのドロップ要素にdropイベントを追加する
for ( var i=0; i < droparea.length ; i++ )
{
  droparea[i].addEventListener("drop", function(evt){
    var id = evt.dataTransfer.getData( "text/plain" );
    var obj1 = document.getElementById( id );

    //ドロップされるdivタグをgetElementById()で取得し直す
    var obj2 = document.getElementById( evt.target.id );

    if( obj1 )
    {
      obj2.appendChild( obj1 );
    }
    evt.preventDefault();
  },false);

  //2つのイベントでデフォルト動作を抑制する
  droparea[i].addEventListener( "dragenter" , function(evt){
    evt.preventDefault();
  }, false );
  droparea[i].addEventListener( "dragover" , function(evt){
    evt.preventDefault();
  }, false );
}  
</script>

<サンプル>アルファベット文字を、黄色かピンクのエリアにドロップしてみて下さい。

(ドロップエリアの空きスペースにドロップすると問題ありませんが、 文字画像の上にドロップすると、ドラッグ要素が消えてしまうようです)

スクリプトの説明

では上記のサンプルスクリプトを詳しく見ていきましょう。

HTML部分

<div id="dragarea">
<img src="img/a.png" widht="100" height="100" id="a" alt="">
<img src="img/b.png" widht="100" height="100" id="b" alt="">
<img src="img/c.png" widht="100" height="100" id="c" alt="">
<img src="img/d.png" widht="100" height="100" id="d" alt="">
</div>
<div class="dp" id="drop1"></div>
<div class="dp" id="drop2"></div>

まずはdivタグを3つ設置しています。最初のdivタグにid名「dragarea」を付け、 その中に4つの画像タグを記述しています。 各画像にもid名を付けています。

2つ目と3つ目のdivタグはドロップされるエリアを構成します。 この2つにクラス名「dp」を付けました。このクラス名を用いてドロップされるdivタグを特定します。 またid名もそれぞれに付けています。

CSS部分

<style type="text/css">
div#dragarea{ width:100%; height:100px; background-color:#80ffff }
div.dp{ width:50%; height:100px }
div#drop1{ background-color:#ffff80; float:left }
div#drop2{ margin-left:50%; background-color:#ff80ff;  }
div#drop2:after{ content:""; display:block; clear:left }
</style>

次にスタイルシートの意味を説明しておきます。 最初にid名「dragarea」の付いたdivタグの横幅を100%,高さを100px,背景を薄青にしました。

次はクラス名「dp」の付いたdivタグに、横幅50%,高さ100pxの指定をしています。

3行目はid名「drop1」の付いたdivタグの背景色を薄黄色に、 また左寄せして右側に文字を流し込みます。

4行目はid名「drop2」の付いたdivタグの背景色をピンクに、左余白を50%にしています。 このようにすれば、前のdivタグの右側にこちらのdivタグが回り込みます。

5行目はid名「drop2」の付いたdivタグのすぐ後に、空文字の入ったブロック要素を追加しています。 その要素に、左回り込みを解除する指示をしておきます。

imgタグ要素を全て取得する

var elm = document.getElementsByTagName("img");

ここは、前のページと同じです。ページ内にある全てのimgタグを取得し、 変数elmに格納します。

全imgタグにdragstartイベントを追加する

for ( var i=0 ; i < elm.length ; i++ )
{
  elm[i].addEventListener("dragstart", function(evt){
    evt.dataTransfer.setData("text/plain",evt.target.id);
    evt.stopPropagation();
  },false);
}

ここの部分も前のページと同じです。各imgタグにdragstartイベントを追加しています。

クラス名「dp」を持つdivタグを全て取得する

var droparea = document.querySelectorAll("div.dp");

続いて、ドロップされる側を見ていきます。 document.querySelectorAll()を使い、 クラス名「dp」の付いたdivタグを全て取得し、変数dropareaに格納します。 getElementsByClassName("dp")を用いても構いません。

全てのドロップ要素に各種イベントを追加する

for ( var i=0; i < droparea.length ; i++ ){イベント追加処理}

querySelectorAll()で取得した要素は、配列の形になっています。 ですから、lengthを使って要素数を取得できます。 for文を使って、取得した全ての要素にdropイベント、dragenterイベント、dragoverイベントを追加します。

全てのドロップ要素にdropイベントを追加する

droparea[i].addEventListener("drop", function(evt){
  var id = evt.dataTransfer.getData( "text/plain" );
  var obj1 = document.getElementById( id );

  var obj2 = document.getElementById( evt.target.id );

  if( obj1 )
  {
    obj2.appendChild( obj1 );
  }
  evt.preventDefault();
},false);

続いてfor文の中を見ていきましょう。最初にaddEventListener()でdropイベントを追加しています。 ドロップされる各要素は、droparea[i]で指定できます。

まずはdataTransferからドラッグ要素のid名を受取り、変数idに代入しています。 その後getElementById()でドラッグ要素を指定し、変数obj1に格納しました。

次に、ドロップされる側の要素をgetElementById()で取得し直し、変数obj2に代入しています。 id名はevt.target.idで取得すればOKです。 こうするのは、droparea[i].appendChild()と記述してもうまく動作しないからです。

if文でドラッグ要素を掴むのに成功しているか確認し、掴んでいたらappendChild()で要素を移動します。

preventDefault()は、ブラウザでのデフォルトの動作を抑制するためのものです。

2つのイベントでデフォルト動作を抑制する

droparea[i].addEventListener( "dragenter" , function(evt){
  evt.preventDefault();
}, false );
droparea[i].addEventListener( "dragover" , function(evt){
  evt.preventDefault();
}, false );

いつものように2つのイベントでブラウザのデフォルト動作を抑制します。 これもfor文の中で記述し、全てのドロップ要素に対応させます。