[JS] ドラッグ&ドロップ その2

タグ :

jQuery の勉強をまとめるシリーズです。
今回も前回に続いてドラッグ&ドロップについてです。

前記事と全く同じアプリですが、今回はドロップ時の HTML の表示変更処理についてまとめます。
基本的な jQuery UI の設置と設定については前記事「ドラッグ&ドロップ」を参照してください。

アプリ概要

アプリと言っても UI を使えばこんなに簡単にドラッグ&ドロップを利用できますよー、ということをまとめるために作成するだけです。ちょっとだけ遊べるってだけのものです。

以下のような仕様とします。

ドロップ領域にボックスをドロップ可能
 - ドラッグしたボックスのコピーをドロップ領域に表示する
 - ドロップできるボックスは領域に対して2色までとする
 - 同じ色のボックスをドロップした場合は追加表示しない
ドロップしたボックスの個数をカウント
 - 同じ色のボックスをドロップした場合にカウントする
 - カウント値はドロップしたボックスの下部に表示する

必要となる処理は以下になります。

  • 動的にクラスを変更
  • 動的にテキストを変更
  • 要素の内容確認
  • 要素のテキスト確認

作成したサンプル

処理の流れとコードは以下になります。

[ 動作フロー ]
js_dragdrop_flow
[ コード ]
jQuery のコード以外は前記事と全く同じです。また、ドラッグ&ドロップのメソッド draggable() と droppable() の部分は前記事を参照してください。
$(function() {
	/* 〜 draggable(),droppable() は省略 〜 */
	function boxDropping(ui, obj) {
		var tag = '';
		var flg = true;
		$('div',obj).each(function(i) {
			if($(this).attr('class') == ui.draggable.attr('class')) {
				tag = 'p.val' + (i + 1);
				if($(tag,obj).text()) {
					var arr = $(tag,obj).text().split(" ");
					var val = parseInt(arr[1]) + 1;
				} else {
					var val = 2;
				}
				$(tag,obj).text('× ' + val);
				flg = false;
			} else {
				tag = 'div.box' + (i + 1);
				if($(tag,obj).size()) {
					$(tag,obj).addClass(ui.draggable.attr('class'));
					$(tag,obj).html(ui.draggable.html());
					$(tag,obj).removeClass('box' + (i + 1));
					flg = false;
				}
			}
			return flg;
		});
	}
});
<h4>ドラッグ&ドロップ</h4>
<div class="main">
	<div class="draglist">
		<div class="red">
			<p>Red</p>
		</div>
		<div class="green">
			<p>Green</p>
		</div>
		<div class="blue">
			<p>Blue</p>
		</div>
	</div>
	<div class="droparea">
		<div class="drop1">
			<p>ドロップ領域1</p>
			<p>accept = Red, Blue<br />tolerance = 'fit'</p>
			<div class="box1"></div>
			<div class="box2"></div>
			<p class="val1"></p>
			<p class="val2"></p>
		</div>
		<div class="drop2">
			<p>ドロップ領域2</p>
			<p>accept = Green, Blue<br />tolerance = 'touch'</p>
			<div class="box1"></div>
			<div class="box2"></div>
			<p class="val1"></p>
			<p class="val2"></p>
		</div>
	</div>
</div>
.main {
	width: 600px; height: 410px; background: #ccc;
}
.draglist {
	float: left; margin-top: 20px;
	width: 600px; height: 100px;
}
.red, .green, .blue {
	float: left; margin-left: 20px; cursor: move;
	width: 100px; height: 100px;
}
.red {
	background: red;
}
.green {
	background: green;
}
.blue {
	background: blue;
}
.red p, .green p, .blue p {
	margin-top: 40px; text-align: center;
}
.dragout {
	opacity: 0.4;
}
.droparea {
	float: left; margin-top: 20px;
	width: 600px; height: 250px;
}
.drop1, .drop2 {
	float: left; margin-top: 0px;
	width: 260px; height: 250px; background: gray;
	border: 2px solid black;
}
.drop1 {
	margin-left: 20px;
}
.drop2 {
	margin-left: 30px;
}
.drop1 > p, .drop2 > p {
	margin-top: 5px; margin-bottom: 0px;
	text-align: center;
}
.drop1 div, .drop2 div {
	float: left; margin-top: 20px; cursor: default;
	width: 100px; height: 100px;
}
.drop1 p.val1, .drop1 p.val2,
.drop2 p.val1, .drop2 p.val2 {
	float: left; margin-left: 20px; width: 100px;
}
.active {
	border: 2px solid red;
}
.hover {
	background: #ccc;
}
詳しい説明は後述します。
「boxDropping()」という関数を用意し、そこで HTML 表示変更処理を行います。ドロップ時の処理内でこの関数を呼び出して使用しています。

コード解説

jQuery のコードの説明をします。

[ jQuery の説明 ]
[ 2行目 関数呼び出し ]
/* 〜 draggable(),droppable() は省略 〜 */

droppable() 内のオプション「drop:」内の処理に「boxDropping(ui, $(this))」と記述して関数を呼び出します。引数には、ドラッグ要素のオブジェクト変数とドロップ要素のオブジェクト変数を渡します。
また、前記事にてドラッグ時に元の要素に「dragout」というクラス名を追加していますが、この後の処理のクラス名判定で邪魔になりますので、削除しておく必要があります。関数を呼び出す直前に「ui.draggable.removeClass(‘dragout’);」でクラス名を削除しておきます。

[ 6行目 HTML要素内ループ ]
$('div',obj).each(function(i) {

HTML のドロップ領域内の div 要素の数分だけループします。今回は div は2つしかないので、最大で2回ループを実行します。

[ 7行目 ドロップ要素のクラス名判定 ]
if($(this).attr('class') == ui.draggable.attr('class')) {

ドロップした要素のクラス名と現在表示中の div 要素のクラス名を比較します。一致した場合は既に要素が存在しているということなので、カウント加算処理へ移行します。一致しなかった場合はボックス追加処理へ移行します。

[ 8行目〜9行目 テキスト有無判定 ]
tag = 'p.val' + (i + 1);

ドロップ領域内の p 要素を指定します。p 要素のクラス名は「val1」、「val2」と語尾に数値を付けて指定しているので、ループで使用している変数「i」を用います。

if($(tag,obj).text()) {

指定した p 要素のテキストの有無を判定します。記述が有るなら、既にカウント済み(3回目以降のドロップ)ということになるので、取得&加算処理へ移行します。記述が無いなら、未だカウントされていない(2回目のドロップ)ということになるので、カウント値に「2」を記述するために処理へ移行します。

[ 10行目〜11行目 カウント数値の取得&加算 ]
var arr = $(tag,obj).text().split(" ");

現在記述されているカウント値を取得します。テキストには「× 2」というような記述がされているはずなので、取得してから「スペース」で文字列分割して数値を取得します。

var val = parseInt(arr[1]) + 1;

取得した数値を変数「val」に代入します。取得して文字列分割したものを格納した変数「arr」の2番目(要素番号が1)にカウント数値が入っているので「arr[1]」を用います。さらに文字列を数値化するメソッド(parseInt)を用いて数値として扱います。変数「val」への代入時に +1 加算しておきます。

[ 15行目 カウント値の記述 ]
$(tag,obj).text('× ' + val);

HTML の指定した p 要素へテキストを記述します。テキストには「× 」という文字列とカウント値を格納した変数を記述します。

[ 18行目〜19行目 ドロップ領域空き判定 ]
tag = 'div.box' + (i + 1);
if($(tag,obj).size()) {

ドロップ領域内の div 要素を指定します。div 要素のクラス名は「box1」、「box2」と語尾に数値を付けて指定しているので、ループで使用している変数「i」を用います。

[ 20行目〜22行目 クラス名と要素の変更 ]
$(tag,obj).addClass(ui.draggable.attr('class'));

指定したドロップ領域の div 要素のクラス名を追加します。追加するクラス名はドラッグした要素のクラス名です。引数で得たドラッグ要素のオブジェクト変数「ui」からクラス名を引っ張ってきます。

$(tag,obj).html(ui.draggable.html());

指定したドロップ領域の div 要素を変更します。ドラッグした要素に変更します。引数で得たドラッグ要素のオブジェクト変数「ui」から要素を引っ張ってきます。

$(tag,obj).removeClass('box' + (i + 1));

指定したドロップ領域の div 要素の余分なクラス名を削除します。削除するクラス名は初期状態(ドロップ前)で指定したもの「box1」か「box2」です。ここで削除しておくことで、7行目で行うクラス名判定を正しく行うようにしています。

[ 16行目,23行目 ループの強制終了 ]
flg = false;

カウント値を記述した後とボックスを追加した後は、もう次の要素を確認する必要はないので、ループを終了させます。「return false」の記述で each ループを終了させることができます。今回は変数「flg」を用いて終了するか否かを決めています。

まとめ

今回のサンプルではクラス名を変更することで表示を切り替える方法でドロップ表示を実現しています。ドラッグ&ドロップでの表示にはこの方法以外に append(), appendTo() による要素を追加挿入して行う方法があります。追加挿入による方法では予め領域を確保しておく必要が無いので、実用的ではあると思います。ただ、今回のようにテキストも追加させるとなると CSS による配置がややこしくなりがちです。今回もそれが面倒くさくなってクラスを変更する方法を用いました。

2部に渡ってドラッグ&ドロップをまとめてきましたが、これといって苦労した点はありません。CSS による配置くらいです。今後もこのドラッグ&ドロップ機能を活用して、操作性の良いサイトを作成していけたらなと思います。

Share

  • このエントリーをはてなブックマークに追加

Comment

コメントを残す

*がついている欄は必須項目です。

  • Twitter
  • Facebook
  • Google Plus
  • RSS Feed