jQuery draggable zeigt den Helfer an der falschen Stelle an, nachdem die Seite gescrollt wurde


79

Ich verwende jQuery ziehbar und ablegbar für ein Arbeitsplanungssystem, das ich entwickle. Benutzer ziehen Jobs an einen anderen Tag oder Benutzer, und dann werden die Daten mithilfe eines Ajax-Aufrufs aktualisiert.

Alles funktioniert einwandfrei, außer wenn ich auf der Hauptseite nach unten scrolle (Jobs werden in einem großen Wochenplaner angezeigt, der den unteren Rand meines Browserfensters überschreitet). Wenn ich versuche, ein ziehbares Element hierher zu ziehen, wird das Element über meinem Mauszeiger mit der gleichen Anzahl von Pixeln angezeigt, die ich nach unten gescrollt habe. Der Schwebezustand funktioniert immer noch einwandfrei und die Funktionalität ist aktiviert, sieht aber nicht richtig aus.

Ich verwende jQuery 1.6.0 und jQuery UI 1.8.12.

Ich bin sicher, dass ich eine Offset-Funktion hinzufügen muss, aber ich weiß nicht, wo ich sie anwenden soll oder ob es einen besseren Weg gibt. Hier ist mein .draggable()Initialisierungscode:

$('.job').draggable({
  zIndex: 20,
  revert: 'invalid',
  helper: 'original',
  distance: 30,
  refreshPositions: true,
});

Irgendeine Idee, was ich tun kann, um das zu beheben?



@jimy es ist alles dynamisch und sehr sicher, also müsste ich ein ganz neues Beispiel schreiben; Ich werde es tun, wenn niemand so schnell wie möglich eine schnelle Antwort hat.
Alex

Können Sie alle CSS-Eigenschaften veröffentlichen, die Ihr Draggable hat oder erbt?
DarthJDG

2
Nach meiner Antwort weit unten scheint dies endgültig behoben zu sein
Patrick

Antworten:


107

Dies könnte ein verwandter Fehlerbericht sein, den es schon eine ganze Weile gibt: http://bugs.jqueryui.com/ticket/3740

Es scheint in jedem von mir getesteten Browser (Chrome, FF4, IE9) zu passieren. Es gibt einige Möglichkeiten, wie Sie dieses Problem umgehen können:

1. Verwenden Sie position:absolute;in Ihrem CSS. Absolut positionierte Elemente scheinen nicht betroffen zu sein.

2. Stellen Sie sicher, dass das übergeordnete Element (Ereignis, wenn es sich um den Body handelt) overflow:auto;festgelegt wurde. Mein Test hat gezeigt, dass diese Lösung die Position korrigiert, aber die Autoscroll-Funktionalität deaktiviert. Sie können weiterhin mit dem Mausrad oder den Pfeiltasten scrollen.

3. Wenden Sie das im obigen Fehlerbericht vorgeschlagene Update manuell an und testen Sie es gründlich, wenn es andere Probleme verursacht.

4. Warten Sie auf eine offizielle Lösung. Es ist für jQuery UI 1.9 geplant, obwohl es in der Vergangenheit einige Male verschoben wurde.

5. Wenn Sie sicher sind, dass dies in jedem Browser geschieht, können Sie diese Hacks in die Ereignisse der betroffenen Draggables einfügen, um die Berechnungen zu korrigieren. Es sind jedoch viele verschiedene Browser zu testen, daher sollte es nur als letzter Ausweg verwendet werden:

$('.drag').draggable({
   scroll:true,
   start: function(){
      $(this).data("startingScrollTop",$(this).parent().scrollTop());
   },
   drag: function(event,ui){
      var st = parseInt($(this).data("startingScrollTop"));
      ui.position.top -= $(this).parent().scrollTop() - st;
   }
});

12
Das ist super, Danke! (Einstellungen Überlauf: sofort automatisch behoben. Ich habe den Stil auf die einzelnen Tabellenzellen angewendet.
Alex

2
jsfiddle.net/a2hzt/5 overflow-y: Das Scrollen im HTML-Element verursacht dieses Problem auch in Firefox (Chrome funktioniert). Scrollen Sie einfach nach unten und versuchen Sie es mit einem Drag & Drop.
digitalPBK

8
Es ist ba-a-ack, z helper: "clone". bugs.jqueryui.com/ticket/9315 Ebene Blocker , eine Kerbe über Dur. tj.vantoll sagt, "6 ziehbare Korrekturen, die in 1.10.3 gelandet sind, könnten verdächtig sein." Das bisher einfachste
Bob Stein

7
Bestätigt, dieser Fehler ist in jQuery UI 1.10.3, aber nicht in 1.10.2
Bob Stein

2
Das Problem scheint auch in jQuery UI 1.10.4 vorhanden zu sein . Ich bleibe vorerst bei 1.10.2 !
lhan

45

Diese Lösung funktioniert, ohne die Position von irgendetwas anzupassen. Sie klonen einfach das Element und machen es absolut positioniert.

$(".sidebar_container").sortable({
  ..
  helper: function(event, ui){
    var $clone =  $(ui).clone();
    $clone .css('position','absolute');
    return $clone.get(0);
  },
  ...
});

Der Helfer kann eine Funktion sein, die das DOM-Element zum Ziehen zurückgeben muss.


+1 Vielen Dank, das funktioniert bei mir mit sortierbar (ich wollte gerade etwas Ähnliches, aber weniger Elegantes ausprobieren). Sie haben einen kleinen Tippfehler mit $ j! :)
Iain Collins

4
Für mich: Drag funktioniert damit überhaupt nicht und gibt Fehler zurück: TypeError: this.offsetParent [0] ist undefiniert
ProblemsOfSumit

Ich denke, es ist ui.helper nicht nur ui
Mohammed Joraid

1
Vielen Dank, dass Sie mir mit Sortable
BG BRUNO

1
Dies ist die einzige Antwort, die für mich funktioniert, und sie ist am einfachsten zu implementieren. Tolle Lösung
Brett Gregson

11

Das hat bei mir funktioniert:

start: function (event, ui) {
   $(this).data("startingScrollTop",window.pageYOffset);
},
drag: function(event,ui){
   var st = parseInt($(this).data("startingScrollTop"));
   ui.position.top -= st;
},

behebe mein Problem,"1.11.0"
21елёный

Das ist eine lustige Lösung, aber sie funktioniert nur in Browsern mit dem Fehler (Chrome). Browser, die den Fehler nicht haben, haben ihn jetzt aber invertiert :)
Manu

Hinweis: Einige JS-Parser beschweren sich möglicherweise über "fehlende Radix", wenn sie diese Lösung verwenden. Um dies zu beheben, ersetzen Sie var st = parseInt ($ (this) .data ("StartingScrollTop")); mit var st = parseInt ($ (this) .data ("StartingScrollTop"), 10); (dh geben Sie das zu verwendende Zahlensystem an). 10 ist die Standardeinstellung, aber einige Parser verlangen möglicherweise, dass dies dennoch vorhanden ist (z. B. Webpack)
ripper17

7

Entschuldigen Sie, dass Sie eine weitere Antwort geschrieben haben. Da keine der Lösungen in der obigen Antwort von mir verwendet werden konnte, habe ich viel gegoogelt und viele frustrierende kleinere Änderungen vorgenommen, bevor ich eine andere vernünftige Lösung gefunden habe.

Dieses Problem scheint auftreten , wenn jede der übergeordneten Elemente positionauf ‚relativ‘. Ich musste mein Markup neu mischen und mein CSS ändern, aber durch Entfernen dieser Eigenschaft von allen Eltern konnte ich .sortable()in allen Browsern ordnungsgemäß arbeiten.


Das gleiche gilt für mich hier. Jeder position: relative;in einem Elternteil bewirkt dies.
Wojtiku

total einverstanden! Für mich war es nur ein Inline-Stil im Körper, mit position: relative;dem entfernt werden musste. Übergeordnete Elemente zwischen dem ziehbaren und dem Körper scheinen hier keine Probleme zu machen.
con

1
omg das war es danke, garrr warum benutzen die Leute heutzutage Dragula nicht - danke!
Dominic

Ich danke dir sehr! Elternteil des Elternteils mit Position: Verwandter hat es für mich verursacht
wjk2a1

7

Es sieht so aus, als ob dieser Fehler sehr häufig auftritt und jedes Mal gibt es eine andere Lösung. Nichts davon oder irgendetwas anderes, was ich im Internet gefunden habe, hat funktioniert. Ich verwende jQuery 1.9.1 und Jquery UI 1.10.3. So habe ich es behoben:

$(".dragme").draggable({
  appendTo: "body",
  helper: "clone",
  scroll: false,
  cursorAt: {left: 5, top: 5},
  start: function(event, ui) {
    if(! $.browser.chrome) ui.position.top -= $(window).scrollTop();
  },
  drag: function(event, ui) {
    if(! $.browser.chrome) ui.position.top -= $(window).scrollTop();
  }
});

Funktioniert in FF, IE, Chrome, ich habe es noch nicht in anderen Browsern getestet.


1
Dies funktionierte für mich, außer dass ich ui.offset.top anstelle von ui.position.top verwenden musste
c.dunlap

5

Ich lösche den Überlauf:

html {overflow-y: scroll; background: #fff;}

Und es funktioniert perfekt!


5

Dieser Fehler wurde auf http://bugs.jqueryui.com/ticket/6817 verschoben und scheint seit ungefähr 5 Tagen (16. Dezember 2013 oder so ungefähr) endlich behoben worden zu sein. Derzeit wird empfohlen, den neuesten Entwicklungs-Build von http://code.jquery.com/ui/jquery-ui-git.js zu verwenden oder auf Version 1.10.4 zu warten, die diesen Fix enthalten sollte .

Bearbeiten: Es scheint, dass dieses Update jetzt Teil von http://bugs.jqueryui.com/ticket/9315 ist, das erst in Version 1.11 gelöscht werden soll. Die Verwendung der oben verlinkten Versionsverwaltungsversion von jQuery scheint das Problem für mich und @Scott Alexander zu beheben (Kommentar unten).


Ich benutze 1.10.4 und der Fehler ist immer noch da, habe diesen Link benutzt und alles funktioniert gut.
Scott Alexander

@ScottAlexander Das Update wurde möglicherweise an ein anderes Ticket angehängt als ich dachte. Ich habe meine Antwort darauf basierend bearbeitet. Vielen Dank!
Patrick

4

Scheint bemerkenswert, dass dieser Fehler so lange behoben sein sollte. Für mich ist es ein Problem unter Safari und Chrome (dh den Webkit-Browsern), aber weder unter IE7 / 8/9 noch unter Firefox, die alle einwandfrei funktionieren.

Ich fand, dass das Setzen von absolut oder fest, mit oder ohne! Wichtig, nicht hilfreich war. Am Ende fügte ich meiner Drag-Handler-Funktion eine Zeile hinzu:

ui.position.top += $( 'body' ).scrollTop();

Ich hatte erwartet, dass ich diese Zeile webkit-spezifisch machen musste, aber seltsamerweise funktionierte sie überall gut. (Erwarten Sie bald einen Kommentar von mir, der sagt: "Ähm, nein, tatsächlich hat er alle anderen Browser durcheinander gebracht."


1
Dies funktioniert, aber wenn Sie beim Ziehen scrollen, wird die y-Position immer noch verschoben. Die Lösung Nr. 5 des DarthJDG funktioniert auch beim Scrollen beim Ziehen.
Mirelon

3

Was ich getan habe ist:

$("#btnPageBreak").draggable(
        {
          appendTo: 'body',
          helper: function(event) {
            return '<div id="pageBreakHelper"><img  id="page-break-img"  src="page_break_cursor_red.png" /></div>';
          },
          start: function(event, ui) {
          },
          stop: function(event, ui) {
          },
          drag: function(event,ui){
            ui.helper.offset(ui.position);
         }
        });

1

Ich bin mir nicht ganz sicher, ob dies in jedem Fall funktionieren wird, aber diese Problemumgehung, die ich gerade für mich in all den verschiedenen Situationen durchgeführt habe, die ich testen musste (und in denen die zuvor hier und anderswo angegebenen Lösungsvorschläge alle fehlgeschlagen sind).

(function($){
$.ui.draggable.prototype._getRelativeOffset = function()
{
    if(this.cssPosition == "relative") {
        var p = this.element.position();
        return {
            top: p.top - (parseInt(this.helper.css("top"),10) || 0)/* + this.scrollParent.scrollTop()*/,
            left: p.left - (parseInt(this.helper.css("left"),10) || 0)/* + this.scrollParent.scrollLeft()*/
        };
    } else {
        return { top: 0, left: 0 };
    }
};
}(jQuery));

(Ich habe es an den jQuery.ui-Tracker gesendet, um zu sehen, was sie darüber denken. Es wäre cool, wenn dieser 4 Jahre alte Fehler endlich behoben werden könnte: /)


1

Ich verwende JQuery Draggable unter Firefox 21.0 und habe das gleiche Problem. Der Cursor bleibt einen Zentimeter über dem Hilfsbild. Ich denke, dies ist ein Problem in der Jquery selbst, das noch nicht gelöst wurde. Ich habe eine Problemumgehung für dieses Problem gefunden, bei der die Eigenschaft "cursorAt" der Dragable verwendet wird. Ich habe es wie folgt verwendet, aber man kann dies entsprechend seiner Anforderung ändern.

$('.dragme').draggable({
helper: 'clone',    
cursor: 'move',    
cursorAt: {left: 50, top: 80}
});

Hinweis: Dies gilt für alle Browser. Überprüfen Sie nach Verwendung dieses Codes Ihre Seite in allen Browsern, um die richtigen Positionen für links und oben zu erhalten.


1

Dies hat bei mir funktioniert, nachdem ich alles angepasst habe, was ich über das Problem gelesen habe.

$(this).draggable({
  ...
  start: function (event, ui) {
    $(this).data("scrollposTop", $('#elementThatScrolls').scrollTop();
    $(this).data("scrollposLeft", $('#elementThatScrolls').scrollLeft();
  },
  drag: function (event, ui) {
    ui.position.top += $('#elementThatScrolls').scrollTop();
    ui.position.left += $('#elementThatScrolls').scrollLeft();
  },
  ...
}); 

* elementThatScrolls ist das übergeordnete Element oder der Vorfahr mit Überlauf: auto;

Berechnet die Position des Bildlaufelements und erhöht die Position des Hilfsprogramms bei jedem Verschieben / Ziehen.

Hoffe das hilft jemandem, da ich viel Zeit damit verschwendet habe.


1

Dies scheint die Problemumgehung zu tun, ohne dass die Position verwendet werden muss: absolut im übergeordneten Element :)

$("body").draggable({
     drag: function(event, ui) { 
         return false; 
     } 
});

Vielen Dank! Dies ist das einzige, was für mich funktioniert hat. (Ich bin nicht sicher, ob ich das Problem verstehe. Mein Problem ist, dass das Ziehen und Ziehen des Bildlaufs gut funktioniert, wenn das Ziehen mit der Bildlaufleiste oben beginnt. Wenn die Bildlaufleiste niedriger beginnt, tritt ein Versatzproblem auf.)
John Smith

1

Ich habe es geschafft, das gleiche Problem beim Hinzufügen zu beheben display: inline-block zu den gezogenen Elementen

Das Hinzufügen position: relativehat bei mir NICHT funktioniert (jQuery überschreibt es mitposition: absolute Drag-Start)

Verwendete jQuery-Versionen:

  • jQuery - 1.7.2
  • jQuery UI - 1.11.4

position: relativeMöglicherweise hat es funktioniert, wenn Sie es in ein übergeordnetes Containerelement verschoben haben. Ich weiß, dass es jetzt nicht hilft, sondern nur als Referenz und vielleicht für einen zukünftigen Entwickler in Schwierigkeiten.
gdibble

1

Ich hatte das gleiche Problem und stellte fest, dass dies alles auf eine Bootstrap-Navbar-Klasse "navbar-fixed-top" mit fester Position zurückzuführen war, die sich um <body>60 Pixel tiefer als <html>oben bewegte . Als ich also ziehbare Formulare auf meiner Site verschob, erschien der Cursor 60 Pixel über dem Formular.

Sie können sehen, dass Sie im Chrome-Debugging-Tool in der Elements-Oberfläche auf das <body>Tag klicken und eine Lücke zwischen oben und dem Körper sehen.

Da ich diese Navigationsleiste in allen meinen Anwendungen verwende und meinen Initialisierungsaufruf nicht so ändern wollte, dass sie für jedes Formular gezogen wird (gemäß der DarthJDG-Prozedur). Ich habe beschlossen, das ziehbare Widget auf diese Weise zu erweitern und meiner ziehbaren Initialisierung einfach ein yOffset hinzuzufügen.

(function($) {
  $.widget("my-ui.draggable", $.ui.draggable, {
    _mouseDrag: function(event, noPropagation) {

      //Compute the helpers position
      this.position = this._generatePosition(event);
      this.positionAbs = this._convertPositionTo("absolute");

      //Call plugins and callbacks and use the resulting position if something is returned
      if (!noPropagation) {
        var ui = this._uiHash();
        if(this._trigger('drag', event, ui) === false) {
          this._mouseUp({});
          return false;
        }
        this.position = ui.position;
      }
      // Modification here we add yoffset in options and calculation
      var yOffset = ("yOffset" in this.options) ? this.options.yOffset : 0;

      if(!this.options.axis || this.options.axis != "y") this.helper[0].style.left = this.position.left+'px';
      if(!this.options.axis || this.options.axis != "x") this.helper[0].style.top = this.position.top-yOffset+'px';
      if($.ui.ddmanager) $.ui.ddmanager.drag(this, event);

      return false;
    }
  });
})(jQuery);

Wenn ich nun das ziehbare Element / Formular in einer Site mithilfe der Bootstrap-Navigationsleiste initialisiere:

// Make the edit forms draggable
$("#org_account_pop").draggable({handle:" .drag_handle", yOffset: 60});

Natürlich müssen Sie experimentieren, um das richtige yOffset für Ihre eigene Site zu ermitteln.

Trotzdem danke an DarthJDG, der mir die richtige Richtung gezeigt hat. Prost!


0

Ich habe die Verwendung von jQueryUi draggable beendet und ein besseres Plugin namens jquery.even.drag verwendet , eine viel kleinere Codegröße, ohne den ganzen Mist, den jQueryUI hat.

Ich habe eine Demoseite mit diesem Plugin in einem Container erstellt, dessen Position: fest ist

Demo

Hoffe das hilft jemandem, denn dieses Problem ist GROSS.


0

Ich hatte ein ähnliches Problem, nur mit einem bestimmten IE 10 unter Windows 8. Alle anderen Browser funktionierten einwandfrei. Das Entfernen von cursorAt: {top: 0} hat das Problem behoben.


0

Ich habe hier verschiedene Antworten ausprobiert, einschließlich der Aktualisierung von jQuery, und festgestellt, dass dies für mich funktioniert. Ich habe dies auf neuestem Chrome und IE getestet. Ich denke, dies wird ein Problem mit unterschiedlichen Lösungen sein, abhängig von Ihrem UI-Layout.

$('{selector}').draggable({
    start: function(event, ui) {
        ui.position.top -= $(document).scrollTop();
    },
    drag: function(event, ui) {
        ui.position.top -= $(document).scrollTop();
    }
});

0

Warum nicht die Cursorposition einnehmen? Ich benutze das sortierbare Plugin und behebe es mit diesem Code:

sort: function(e, ui) {
    $(".ui-sortable-handle.ui-sortable-helper").css({'top':e.pageY});
}

0

Verwenden appendTo: "body'und Position einstellen mit cursorAt. Das funktioniert gut von mir.

Beispiel für mein Symbol, das dem Mauszeiger auch nach dem Scrollen der Seite folgt

$('.js-tire').draggable
      tolerance: 'fit',
      appendTo: 'body',
      cursor: 'move',
      cursorAt:
        top: 15,
        left: 18
      helper: (event) ->
        $('<div class="tire-icon"></div>').append($('<img src="/images/tyre_32_32.png" />'))
      start: (event, ui) ->
        if $(event.target).hasClass 'in-use'
          $('.js-send-to-maintenance-box').addClass 'is-highlighted'
        else
          $('.ui-droppable').addClass 'is-highlighted'
      stop: (event, ui) ->
        $('.ui-droppable')
          .removeClass 'is-highlighted'
          .removeClass 'is-dragover'

0

Ich benutze oben ein klebriges Navi und dachte, das war der Grund für das Scroll-Problem, das alle anderen zu haben scheinen. Ich habe die Idee aller anderen mit cursorAt ausprobiert, ich habe versucht, sie einzudämmen, und nichts hat funktioniert, außer dass ich meinen HTML-Überlauf im CSS aufgehoben habe! Wahnsinnig, wie ein bisschen CSS alles vermasselt. Das habe ich getan und es funktioniert wie ein Zauber:

html {
  overflow-x: unset;
}

body {
  overflow-x: hidden;
}
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.