Beispiel:JS-Anw-Drag and Drop.html

Aus SELFHTML-Wiki
Wechseln zu: Navigation, Suche
<!DOCTYPE html>
<html lang="de">
	<head>
		<meta charset="UTF-8" />
		<meta name="viewport" content="width=device-width, initial-scale=1.0">
		<link rel="stylesheet" media="screen" href="./Beispiel:SELFHTML-Beispiel-Grundlayout.css" />  
		<title>Beispiel Drag 'n Drop</title>
		<style>
			body { min-height: 200vh }
			#outer div { display: flex; align-items: center; justify-content: center; border: 1px solid black; width: 200px; height: 200px; }
			.draggable { position: absolute; background-color: magenta; }
			.draggable p { border: 1px dashed black; padding: .5em; }
			.draggable button, .fixed button { position: absolute; padding: .5em; right: 0; top: 0; }
			.fixed { position: relative; }
			button { padding: .5em; }
		</style>

		<script>
		
			// Erzeugen weiterer Quadrate und de Eventhandler für den Close-Button

			document.addEventListener("DOMContentLoaded", function() {

				let i = 0, x0 = 0, y0 = 130;
				const farben = ["red","green","blue","yellow","orange","magenta"] ;
			
				document.querySelector("#b1").addEventListener("click",function() {
					let newdiv = document.querySelector("#Lager .draggable").cloneNode(true);
					newdiv.style.left = x0 + i*30 + "px";
					newdiv.style.top  = y0 + i*30 + "px";
					newdiv.style.backgroundColor = farben[i%farben.length];
					i++;
					if(i>2*farben.length) { 
						i = 0; 
						x0 += 30;
					}
					document.querySelector("#outer").appendChild(newdiv) ;
				},false);
				
				document.querySelector("#b2").addEventListener("click",function() {
					let newdiv = document.querySelector("#Lager .fixed").cloneNode(true);
					document.querySelector("#outer").appendChild(newdiv) ;
				},false);
				
				document.body.addEventListener("click", function(e) {
					if(e.target.classList && e.target.classList.contains("close")) e.target.parentNode.parentNode.removeChild(e.target.parentNode);
				}, false);
		
			}, false);
		
			// drag_n_drop.js
			// 6. 1. 2021
			// Alle Elemente mit der Klasse "draggable" werden verschiebbar gemacht
			
			document.addEventListener("DOMContentLoaded", function() {
			
				"use strict"

				// Klasse für verschiebbare Elemente
				const drag_class = "draggable";
				
				// Prüfen, welche Eventmodelle unterstützt werden und welches verwendet werden soll
				const pointer_event = ("PointerEvent" in window);
				const touch_event = ("TouchEvent" in window) && !pointer_event;
				
				// Einige Variablen
				let pos0;           // Pointerposition bei down
				let start;          // Position des Dragobjekts bei down
				let zmax = 1000;    // Start z-Index für die Dragelemente, muss evtl. angepasst werden
				let dragele = null; // Das aktuelle Dragelement
			
				// Bestimmen der Pointerposition
				function get_pointer_pos(e) {
					let posx=0, posy=0;
					if(touch_event && e.targetTouches && e.targetTouches[0] && e.targetTouches[0].clientX) {
						posx = e.targetTouches[0].clientX;
						posy = e.targetTouches[0].clientY;
					}
					else if(e.clientX) {
						posx = e.clientX ;
						posy = e.clientY ;
					}
					return {x: posx, y: posy};
				} // get_pointer_pos
				
				//Eventhandler für pointerdown, touchstart oder mousedown
				function handle_down(e) { 
					const pos = get_pointer_pos(e);
					down(e,pos);
				} // handle_down

				//Eventhandler für pointermove, touchmove oder mousemove
				function handle_move(e) {
					const pos = get_pointer_pos(e);
					move(e,pos);
				} // handle_move

				//Eventhandler für pointerup, touchend oder mouseup
				function handle_up (e) {
					up(e);
				} // handle_up

				//Eventhandler für keydown
				function handle_keydown(e) {
					const keyCode = e.keyCode;
					let xwert = 0, ywert = 0;
					if(keyCode && (keyCode==27 || keyCode==37 || keyCode==38 || keyCode==39 || keyCode==40)) { 
						let delta = e.shiftKey?10:1;
						down(e,{x: 0,y: 0});
						switch(keyCode){
							case 37: // links
								xwert = -delta;
								break;
							case 38: // rauf
								ywert = -delta;
								break;
							case 39: // rechts
								xwert = delta;
								break;
							case 40: // runter
								ywert = delta;
								break;
							case 27: // Escape
								esc();
								up(e);
								return;
								break;
						}
						move(e,{x: xwert,y:ywert});
						up(e);
					}
				} // keydown
			
				// Auswahl des Dragelements und Start der Dragaktion
				function down(e,pos) {
					const target = parent(e.target,drag_class);
					if(target) {
						document.body.style.touchAction = "none";
						e.preventDefault();
						dragele = target;
						start = {x: dragele.offsetLeft, y: dragele.offsetTop};
						pos0 = pos;
						dragele.style.zIndex = ++zmax;
						dragele.focus();
					}
				} // down
			
				// Bewegen des Dragelements
				function move(e,pos) {
					if(dragele) {
						e.preventDefault();
						dragele.style.left = (start.x + pos.x - pos0.x) + "px";
						dragele.style.top =  (start.y + pos.y - pos0.y) + "px";
					}
				} // move
		
				// Ende der Aktion
				function up(e) { 
					if(dragele) {
						dragele = null;
						document.body.style.touchAction = "auto";
					}
				} // up
			
				// Defokussieren bei ESC-Taste
				function esc() {
					if(dragele) dragele.blur();
				} // esc

				// Dragbares Element mit Tab-Index für die Fokussierbarkeit und Eventhandler für Unterdrückung der Standardaktion versehen
				function finish(ele) {
					ele.tabIndex = 0;
					if(!pointer_event) {
						ele.addEventListener("touchmove", function(e) { e.preventDefault() }, false);
					}
				} // finish
				
				// Vorfahrenelement mit Klasse classname suchen
				function parent(child,classname) {
					if(child && "closest" in child) return child.closest("."+classname);
					let ele = child;
					while(ele) {
						if(ele.classList && ele.classList.contains(classname)) return ele;
						else ele = ele.parentElement;
					}
					return null;
				} // parent

				// Alle Eventhandler notieren
				if(pointer_event) {
					document.body.addEventListener("pointerdown",handle_down,false);
					document.body.addEventListener("pointermove",handle_move,false);
					document.body.addEventListener("pointerup",handle_up,false);
				}
				else if(touch_event) {
					document.body.addEventListener("touchstart",handle_down,false);
					document.body.addEventListener("touchmove",handle_move,false);
					document.body.addEventListener("touchend",handle_up,false);
				}
				else {
					document.body.addEventListener("mousedown",handle_down,false);
					document.body.addEventListener("mousemove",handle_move,false);
					document.body.addEventListener("mouseup",handle_up,false);
				}
		
				document.body.addEventListener("keydown",handle_keydown,false);

				// finish für alle verschiebbaren Elemente aufrufen
				const draggable = document.querySelectorAll("." + drag_class);
				for(let i=0;i<draggable.length;i++) {
					finish(draggable[i]);
				}

				// css-Angaben für die Bedienbarkeit
				const style = document.createElement('style');
				style.innerText = "."+drag_class+":focus { outline: 2px solid blue; } "
												+ "."+drag_class+" { position: absolute; cursor: move; touch-action: none; } ";
				document.head.appendChild(style);

				// finish für nachträglich erzeugte verschiebbare Elemente aufrufen
				new MutationObserver(function(mutationsList) {
					for(let i=0;i<mutationsList.length;i++) {
						if (mutationsList[i].type === 'childList') {
							for(let j=0;j<mutationsList[i].addedNodes.length;j++) {
								if(mutationsList[i].addedNodes[j].classList && mutationsList[i].addedNodes[j].classList.contains(drag_class)) {
									finish(mutationsList[i].addedNodes[j]);
								}
							}	
						}
					}
				}).observe(document.body, { childList: true, subtree: true });
		
			},false); // DOMContentLoaded
			
			// Ende drag_n_drop.js

		</script>

	</head>

	<body>
		<h1>Beispiel Drag 'n Drop</h1>
		<p>Die farbigen Quadrate können bewegt werden. Erzeuge <button id="b1">noch ein bewegliches Quadrat</button>, <button id="b2">noch ein festes Quadrat</button>.</p>
		<div id="outer">
			<div class="fixed">Beweg mich nicht<button class="close">X</button></div>
			<div class="draggable"><p>Beweg mich</p><button class="close">X</button></div>
		</div>
		
		<div hidden id="Lager">
			<div class="fixed">Beweg mich nicht<button class="close">X</button></div>
			<div class="draggable"><p>Beweg mich</p><button class="close">X</button></div>
		</div>
	</body>
</html>