Ich versuche, die ziehbare HTML5-API zu verwenden (obwohl mir klar ist, dass sie Probleme hat ). Bisher ist der einzige Showstopper, dem ich begegnet bin, dass ich nicht herausfinden kann, was gezogen wird, wenn ein dragover
oder ein dragenter
Ereignis ausgelöst wird:
el.addEventListener('dragenter', function(e) {
// what is the draggable element?
});
Mir ist klar, dass ich davon ausgehen kann, dass es das letzte Element ist, das ein dragstart
Ereignis auslöst, aber ... Multitouch. Ich habe auch versucht, e.dataTransfer.setData
von der dragstart
zu verwenden, um eine eindeutige Kennung anzuhängen, aber anscheinend ist auf diese Daten von / : nicht zugegriffen werden.dragover
dragenter
Diese Daten sind nur verfügbar, wenn während des Drop-Ereignisses ein Drop auftritt.
Also irgendwelche Ideen?
Update: Zum jetzigen Zeitpunkt scheint HTML5-Drag-and-Drop in keinem größeren mobilen Browser implementiert zu sein, weshalb Multitouch in der Praxis nicht erwähnt wird. Ich möchte jedoch eine Lösung, die garantiert für jede Implementierung der Spezifikation funktioniert, was nicht zu verhindern scheint, dass mehrere Elemente gleichzeitig gezogen werden.
Ich habe unten eine funktionierende Lösung veröffentlicht , aber es ist ein hässlicher Hack. Ich hoffe immer noch auf eine bessere Antwort.
quelle
this
in einemdragenter
/dragover
event-Handler wird auf das Element verwiesen, über das gezogen wird, nicht auf das Element, das gezogen wird. Es ist gleiche.target
. Beispiel: jsfiddle.net/TrevorBurnham/jWCSBAntworten:
Ich wollte hier eine sehr klare Antwort hinzufügen, damit es für jeden offensichtlich ist, der hier vorbeigeht. Es wurde mehrmals in anderen Antworten gesagt, aber hier ist es, so klar ich es machen kann:
dragover
HAT NICHT DIE RECHTE, um die Daten im Drag-Ereignis anzuzeigen.Diese Informationen sind nur während DRAG_START und DRAG_END (Drop) verfügbar.
Das Problem ist, dass es überhaupt nicht offensichtlich und verrückt ist, bis Sie zufällig tief genug über die Spezifikation oder Orte wie hier lesen.
ARBEITSUMGEBUNG:
Als mögliche Umgehung habe ich dem DataTransfer-Objekt spezielle Schlüssel hinzugefügt und diese getestet. Um beispielsweise die Effizienz zu verbessern, wollte ich beim Starten des Ziehens einige Regeln zum Löschen von Zielen nachschlagen, anstatt jedes Mal, wenn ein "Ziehen" auftrat. Zu diesem Zweck habe ich dem dataTransfer-Objekt Schlüssel hinzugefügt, die jede Regel identifizieren, und diese mit "enthält" getestet.
ev.originalEvent.dataTransfer.types.includes("allow_drop_in_non_folders")
Und solche Sachen. Um klar zu sein, dass "Includes" kein Wundermittel ist und selbst zu einem Leistungsproblem werden kann. Achten Sie darauf, Ihre Verwendung und Szenarien zu verstehen.
quelle
JSON.stringify
undJSON.parse
( poc ) übergeben. Sehr unelegantDie kurze Antwort auf meine Frage erweist sich als: Nein . Die WHATWG spec nicht einen Verweis auf das Element in die Länge gezogen wird schaffen , in den (die „Quellenknoten“ in der Spezifikation genannt)
dragenter
,dragover
oderdragleave
Veranstaltungen.Warum nicht? Zwei Gründe:
Erstens basiert die WHATWG-Spezifikation , wie Jeffery in seinem Kommentar hervorhebt, auf der Implementierung von Drag-and-Drop durch IE5 +, die älter war als Multitouch-Geräte. (Zum jetzigen Zeitpunkt implementiert kein großer Multitouch-Browser HTML-Drag & Drop.) In einem "Single-Touch" -Kontext ist es einfach, einen globalen Verweis auf das aktuell gezogene Element zu speichern
dragstart
.Zweitens können Sie mit HTML-Drag & Drop Elemente über mehrere Dokumente ziehen. Das ist genial, aber es bedeutet auch , dass ein Verweis auf das Elemente Befinden in jedem geschleppt
dragenter
,dragover
oderdragleave
Ereignisse würde keinen Sinn machen; Sie können nicht auf ein Element in einem anderen Dokument verweisen. Es ist eine Stärke der API, dass diese Ereignisse auf dieselbe Weise funktionieren, unabhängig davon, ob der Drag aus demselben oder einem anderen Dokument stammt.Die Unfähigkeit, serialisierte Informationen für alle Drag-Ereignisse bereitzustellen, außer für
dataTransfer.types
(wie in meiner Antwort auf die Arbeitslösung beschrieben ), ist eine offensichtliche Lücke in der API. Ich habe der WHATWG einen Vorschlag für öffentliche Daten in Drag-Events vorgelegt , und ich hoffe, Sie werden Ihre Unterstützung zum Ausdruck bringen.quelle
A (sehr unelegant) Lösung ist , einen Selektor als speichern Typ von Daten in dem
dataTransfer
Objekt. Hier ist ein Beispiel: http://jsfiddle.net/TrevorBurnham/eKHap/Die aktiven Zeilen hier sind
e.dataTransfer.setData('text/html', 'foo'); e.dataTransfer.setData('draggable', '');
Dann , in den
dragover
unddragenter
Ereignissene.dataTransfer.types
enthält , die Zeichenfolge'draggable'
, die die Identifikation ist erforderlich , um zu bestimmen , welches Element gezogen wird. (Beachten Sie, dass in Browsern anscheinend Daten für einen erkannten MIME-Typ wie festgelegt werdentext/html
müssen, damit dies funktioniert. Getestet in Chrome und Firefox.)Es ist ein hässlicher, hässlicher Hack, und wenn mir jemand eine bessere Lösung geben kann, werde ich ihm gerne das Kopfgeld gewähren.
Update: Eine Einschränkung, die hinzugefügt werden sollte, ist, dass die Spezifikation nicht nur unelegant ist, sondern auch angibt, dass alle Datentypen in ASCII in Kleinbuchstaben konvertiert werden. Seien Sie also gewarnt, dass Selektoren mit Großbuchstaben oder Unicode nicht funktionieren. Jefferys Lösung umgeht dieses Problem.
quelle
Angesichts der aktuellen Spezifikation glaube ich nicht, dass es eine Lösung gibt, die kein "Hack" ist. Die Petition an die WHATWG ist eine Möglichkeit, dies zu beheben :-)
Erweiterung der "(sehr uneleganten) Lösung" ( Demo ):
Erstellen Sie einen globalen Hash aller Elemente, die gerade gezogen werden:
var dragging = {};
dragstart
Weisen Sie im Handler dem Element eine Drag-ID zu (falls noch keine vorhanden ist), fügen Sie das Element dem globalen Hash hinzu und fügen Sie dann die Drag-ID als Datentyp hinzu:var dragId = this.dragId; if (!dragId) { dragId = this.dragId = (Math.random() + '').replace(/\D/g, ''); } dragging[dragId] = this; e.dataTransfer.setData('text/html', dragId); e.dataTransfer.setData('dnd/' + dragId, dragId);
dragenter
Suchen Sie im Handler die Drag-ID unter den Datentypen und rufen Sie das ursprüngliche Element aus dem globalen Hash ab:var types = e.dataTransfer.types, l = types.length, i = 0, match, el; for ( ; i < l; i++) { match = /^dnd\/(\w+)$/.exec(types[i].toLowerCase()); if (match) { el = dragging[match[1]]; // do something with el } }
Wenn Sie den
dragging
Hash für Ihren eigenen Code privat halten, kann der Code eines Drittanbieters das ursprüngliche Element nicht finden, obwohl er auf die Drag-ID zugreifen kann.Dies setzt voraus, dass jedes Element nur einmal gezogen werden kann. Mit Multi-Touch wäre es wahrscheinlich möglich, dasselbe Element mehrmals mit verschiedenen Fingern zu ziehen ...
Update: Um mehrere Drags für dasselbe Element zu ermöglichen, können wir eine Drag-Anzahl in den globalen Hash aufnehmen: http://jsfiddle.net/jefferyto/eKHap/2/
quelle
Um zu überprüfen, ob es sich um eine Datei handelt, verwenden Sie:
e.originalEvent.dataTransfer.items[0].kind
Um den Typ zu überprüfen, verwenden Sie:
e.originalEvent.dataTransfer.items[0].type
dh ich möchte nur eine einzige Datei jpg, png, gif, bmp zulassen
var items = e.originalEvent.dataTransfer.items; var allowedTypes = ["image/jpg", "image/png", "image/gif", "image/bmp"]; if (items.length > 1 || items["0"].kind != "file" || items["0"].type == "" || allowedTypes.indexOf(items["0"].type) == -1) { //Type not allowed }
Referenz: https://developer.mozilla.org/it/docs/Web/API/DataTransferItem
quelle
originalEvent
es in den meisten Fällen bevölkert ist, auch nicht für Chrome.Sie können bestimmen, was beim Starten des Ziehens gezogen wird, und dies in einer Variablen speichern, die beim Auslösen der Dragover- / Dragenter-Ereignisse verwendet wird:
var draggedElement = null; function drag(event) { draggedElement = event.srcElement || event.target; }; function dragEnter(event) { // use the dragged element here... };
quelle
drag
Kopieren Sie in diesem Fallevent.x
undevent.y
in ein Objekt und legen Sie es als Wert einer expando-Eigenschaft für das gezogene Element fest.function drag(e) { this.draggingAt = { x: e.x, y: e.y }; }
In den
dragenter
unddragleave
Ereignisse das Element , dessen expando Eigenschaftswert finden entspricht derevent.x
undevent.y
des aktuellen Ereignisses.function dragEnter(e) { var draggedElement = dragging.filter(function(el) { return el.draggingAt.x == e.x && el.draggingAt.y == e.y; })[0]; }
Um die Anzahl der Elemente zu verringern, die Sie anzeigen müssen, können Sie die Elemente verfolgen, indem Sie sie einem Array hinzufügen oder eine Klasse im
dragstart
Ereignis zuweisen und diese imdragend
Ereignis rückgängig machen .var dragging = []; function dragStart(e) { e.dataTransfer.setData('text/html', ''); dragging.push(this); } function dragEnd(e) { dragging.splice(dragging.indexOf(this), 1); }
http://jsfiddle.net/gilly3/4bVhL/
Theoretisch sollte dies funktionieren. Ich weiß jedoch nicht, wie ich das Ziehen für ein Touch-Gerät aktivieren soll, daher konnte ich es nicht testen. Dieser Link ist mobil formatiert, aber durch Berühren und Schieben wurde das Ziehen auf meinem Android nicht gestartet. http://fiddle.jshell.net/gilly3/4bVhL/1/show/
Bearbeiten: Nach dem, was ich gelesen habe, sieht es nicht so aus, als würde HTML5 Draggable auf allen Touch-Geräten unterstützt. Können Sie Draggable auf Touch-Geräten verwenden? Wenn nicht, wäre Multi-Touch kein Problem, und Sie können einfach das gezogene Element in einer Variablen speichern.
quelle
drag
Ereignishandler aktualisiere .drag
immer vorher ausgelöst wirddragenter
(die Tatsache, dass es für mich nicht ausgelöst wurde, war auf einen Fehler in einer ganz bestimmten Version von Chrome zurückzuführen). Dies garantiert jedoch nichtx
undy
hat konsistente Werte. Insgesamt ist dies eine kluge Antwort und ich gebe ihr eine +1, aber ich glaube nicht, dass ich sie als Antwort akzeptieren kann.Nach dem, was ich auf MDN gelesen habe, ist das, was Sie tun, richtig.
MDN listet einige empfohlene Drag-Typen auf , z. B. text / html. Wenn jedoch keine geeignet sind, speichern Sie die ID einfach als Text mit dem Typ 'text / html' oder erstellen Sie einen eigenen Typ, z. B. 'application / node-id'.
quelle
text/html
Daten zu speichern , aber Sie können aufgrund des Sicherheitsmodells erst nach dem Löschen auf diese Daten zugreifen. Siehe die Spezifikation , insb. "Sicherheitsmodus."Ich denke, Sie können es erhalten, indem Siee.relatedTarget
See anrufen : http://help.dottoro.com/ljogqtqm.phpOK, ich habe es versucht
e.target.previousElementSibling
und es funktioniert, irgendwie ... http://jsfiddle.net/Gz8Qw/4/ Ich denke, es hängt auf, weil das Ereignis zweimal ausgelöst wird. Einmal für den div und einmal für den Textknoten (wenn er für den Textknoten ausgelöst wird, ist dies der Fallundefined
). Ich bin mir nicht sicher, ob das dich dahin bringt, wo du sein willst oder nicht ...quelle
e.relatedTarget
istnull
. In Firefox ist es etwas seltsamXrayWrapper
.XrayWrapper
Dies ist eine Eigenart der Firefox-Entwicklungstools, die immer dann angezeigt werden, wenn Sieconsole.log
ein DOM-Element verwenden. Auf jeden Fall war das, worüber es gewickelt wurde, das umhüllte Ding, nicht das Schleppbare.e.target.previousElementSibling
funktioniert nur, weil dasdraggable
das Element vor dem Drag-Ziel ist ...