マウスドラッグ、マウスドロップ時の dataTransferプロパティ について

javascript

マウスドラッグ、マウスドロップ時の dataTransferプロパティ について

前回の投稿では、マウスでDOM要素をドラッグ&ドロップすることを試してみました。

このドラッグ&ドロップには単にDOM要素をドラッグして、特定のDOM要素にドロップするという
動作だけではなく、ドラッグ時、ドロップ時にデータを転送する。という利用方法があります。

このデータを転送する処理については

移動
コピー
リンク

という諸方法があり、ドロップ時にそれらの方法を選択した上で処理を決定する。
という方法がアプリケーションの質を向上させるポイントにもなります。

また、最近のブラウザではドラッグ&ドロップを標準化したAPIも整備されてきました。

次の例では、ドラッグ時とドロップ時に、データ転送をする方法として
dataTransferプロパティを使った例を試してみます。

dataTransferプロパティは、DataTransferオブジェクトのプロパティです。

dataTransferを試してみる

画面上のとあるDOM要素をドラッグする際、dragstartイベントが発動されます。

このイベントハンドラの実行時に、dataTransferプロパティに対して、データをセットする
ことができます。

前回の投稿を例にすると、

// ドラッグ開始したとき
element_drag_dom.addEventListener('dragstart', function(e){
	display_status('DRAG DOM : dragstart', 'drag_c');
});

上記の箇所の「ドラッグを開始したとき」の dragstart イベントの箇所です。

このイベントの処理に対して、引数のイベントターゲットに、dataTransferプロパティの
setDataメソッドを使って、値を設定します。

具体的には、以下のように記述します。

// ドラッグ開始したとき
element_drag_dom.addEventListener('dragstart', function(e){
	display_status('DRAG DOM : dragstart', 'drag_c');
	
	e.dataTransfer.setData("text/plain" , e.target.textContent);
	
	e.stopPropagation();
});

上記サンプルの「dataTransfer.setData」の箇所がデータをセットしている箇所です。

この「setData」メソッドは、第一引数にデータタイプを指定し、第二引数に格納するデータを指定します。

上記の例でいうと、データタイプは text/plain 、データは e.target.textContent(ドラッグ中のDOM要素のテキスト「ドラッグ用DOM」)です。

上記のdataTransferプロパティに文字列が格納されている前提として、
今度はドロップ側のDOM要素に対して、dropイベントの中でdataTransferプロパティにgetDataメソッドを使って
中の値を取り出すことができます。

前回のドロップ時の処理は以下のように書きました。

// ドラッグしている要素をドロップした時
element_drop_dom.addEventListener('drop', function(e){
	e.preventDefault();
	display_status('DROP DOM : drop', 'drop_c');
	
	// ドラッグ用DOMを削除する
	element_drag_dom.parentNode.removeChild(element_drag_dom);
	
});

このドロップ時の処理に、「let droptxt = e.dataTransfer.getData(“text/plain”);」を追記し、
dataTransferの値を取り出します。

取り出した値がわかりやすいように、一旦droptxtの変数に格納し、
その変数を「element_drop_dom.innerHTML = droptxt;」に出力します。

処理としては、次のように変更しました。

// ドラッグしている要素をドロップした時
element_drop_dom.addEventListener('drop', function(e){
	e.preventDefault();
	display_status('DROP DOM : drop', 'drop_c');
	
	// ドラッグ用DOMを削除する
	element_drag_dom.parentNode.removeChild(element_drag_dom);
	
	let droptxt = e.dataTransfer.getData("text/plain");
	element_drop_dom.innerHTML = droptxt;

});

このように書くことにより、ドラッグ用のDOMをドロップ領域用のDOMにドロップしたタイミングで
ドラッグ時にdataTransferに格納した文字列が、ドロップ時にドロップ領域用のDOMに出力されることが確認できます。

この初期画面の右下のドロップ要素のDOMの文字列が

この文字列に変更されます。

HTMLの全体は以下のようになります。

<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<title>テストHTML</title>
<style type="text/css">

#drag_dom {
	position: absolute;
	height: 100px;
	width: 150px;
	top: 10px;
	left: 10px;
	background-color: #c0e5ff;
}

#drop_dom {
	position: absolute;
	height: 200px;
	width: 300px;
	top: 300px;
	left: 500px;
	padding: 8px;
	border: 5px solid;
	border-color: #ffbaba;
}

#drop_dom_hover {
	background-color: #998877;
}

#dnd_status_area {
	position: absolute;
	top: 120px;
}

.drag_c {
	color: #28a4fb;
}

.drop_c {
	color: #ff5050;
}

</style>
</head>
<body>

<div id="drag_dom" draggable="true">
	ドラッグ用DOM
</div>

<div id="drop_dom">
	ドロップ領域用DOM
</div>

<div id="dnd_status_area">
	<div>ドラッグ&ドロップの状態【日時 - ステータス】</div>
	<div id="dnd_status"></div>
</div>

<script type="text/javascript">

// ドラッグするDOM要素を取得
let element_drag_dom = document.getElementById("drag_dom");

// ドロップするDOM要素を取得
let element_drop_dom = document.getElementById("drop_dom");

// ステータス表示用配列を用意
let status_queue = [];
let status_i = 0;

//------------------------------------------------
// ドラッグ対象に登録するイベントハンドラ
//------------------------------------------------
// 要素をドラッグしている時
element_drag_dom.addEventListener('drag', function(e){
	display_status('DRAG DOM : drag', 'drag_c');

	// ドラッグ中は、文字列を変更
	element_drag_dom.innerHTML = "ドラッグ中です";

});

// ドラッグ開始したとき
element_drag_dom.addEventListener('dragstart', function(e){
	display_status('DRAG DOM : dragstart', 'drag_c');
	
	e.dataTransfer.setData("text/plain" , e.target.textContent);
	
	e.stopPropagation();
});

// ドラッグが終了した時
element_drag_dom.addEventListener('dragend', function(e){
	display_status('DRAG DOM : dragend', 'drag_c');

	// ドラッグが終わったら、文字列、cssを戻す
	element_drag_dom.innerHTML = "ドラッグ用DOM";
	element_drop_dom.style.backgroundColor = "#ffffff";
});

//------------------------------------------------
// ドロップ対象に登録するイベントハンドラ
//------------------------------------------------
// ドラッグ中の要素がドロップできる場所の上に入ったとき
element_drop_dom.addEventListener('dragenter', function(e){
	display_status('DROP DOM : dragenter', 'drop_c');
});

// dragexitは「dragleave」と同義イベントなので、ここではコメントアウト
//element_drop_dom.addEventListener('dragexit', function(e){
//	display_status('dragexit');
//});

// ドラッグしている要素がドロップできる場所から離れたとき
element_drop_dom.addEventListener('dragleave', function(e){
	display_status('DROP DOM : dragleave', 'drop_c');

	element_drop_dom.style.backgroundColor = "#ffffff";

});

// ドラッグ中の要素がドロップできる場所の上にあるとき
element_drop_dom.addEventListener('dragover', function(e){
	e.preventDefault();
	display_status('DROP DOM : dragover', 'drop_c');
	
	// ドロップできる場所の上にあるとき、メッセージとcssを変更する
	element_drag_dom.innerHTML = "離すと消えるよ";
	element_drop_dom.style.backgroundColor = "#ff5050";
});

// ドラッグしている要素をドロップした時
element_drop_dom.addEventListener('drop', function(e){
	e.preventDefault();
	display_status('DROP DOM : drop', 'drop_c');
	
	// ドラッグ用DOMを削除する
	element_drag_dom.parentNode.removeChild(element_drag_dom);
	
	let droptxt = e.dataTransfer.getData("text/plain");
	element_drop_dom.innerHTML = droptxt;

});

/**
 * 処理ステータスを画面出力する
 */
function display_status(status, dd_class)
{
	// 画面上のDOM要素を取得
	let dnd_status = document.getElementById("dnd_status");

	// 現在日時を取得
	let date_tmp = new Date();
	let date_disp = date_tmp.getFullYear() + "/"
	 + ('0' + (date_tmp.getMonth() + 1)).slice(-2)  + "/"
	 + ('0' + date_tmp.getDate()).slice(-2) + " "
	 + ('0' + date_tmp.getHours()).slice(-2) + ":"
	 + ('0' + date_tmp.getMinutes()).slice(-2) + ":"
	 + ('0' + date_tmp.getSeconds()).slice(-2) + "."
	 + ('00' + date_tmp.getMilliseconds()).slice(-3);

	// ステータスを10個づつの表示用配列へ格納する
	status_queue[status_i] = status;
	status_i++;
	if (status_i >= 30) {
		status_i = 0;
	}

	// キューの内容を画面へ描画する
	dnd_status.innerHTML = '';
	for (let i = 0; i < status_queue.length; i++) {
		dnd_status.innerHTML += date_disp + " - <span class='" + dd_class + "'>" + status_queue[i] + "</span><br />";
	}
}

</script>

</body>
</html>

サーバ上のHTMLはこちら(test1.html)

画面にアクセスして、ドラッグ用DOMをドロップ領域用のDOMへドラッグ&ドロップすると、
ドロップ側のDOMの表示が変わることが確認できます。

dataTransferプロパティに格納できるデータについて

dataTransferプロパティに格納できるデータは文字列だけはないです。

例えば、ブラウザ経由でファイルがドロップされた場合はdataTransfer.filesプロパティにファイル内容がオブジェクトとして格納されます。

また、画面上の単純なDOM要素だけではなく、リスト表示をしている

<ul>タグ内の<li>タグ

に対して、
リストの順をドラッグ&ドロップで並び変える。等の動作も可能になります。

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です