jQuery draggable pokazuje pomocnika w niewłaściwym miejscu po przewinięciu strony

79

Używam przeciągania i upuszczania jQuery dla systemu planowania pracy, który tworzę . Użytkownicy przeciągają zadania do innego dnia lub użytkownika, a następnie dane są aktualizowane przy użyciu wywołania Ajax.

Wszystko działa dobrze, z wyjątkiem sytuacji, gdy przewijam stronę główną w dół (oferty pracy pojawiają się w dużym kalendarzu tygodniowym, który przekracza dolną część okna przeglądarki). Jeśli spróbuję przeciągnąć tutaj element, który można przeciągać, element pojawia się nad moim kursorem myszy z taką samą liczbą pikseli, jaką przewinąłem w dół. Stan najechania nadal działa dobrze, a funkcjonalność działa, ale nie wygląda dobrze.

Używam jQuery 1.6.0 i jQuery UI 1.8.12.

Jestem pewien, że muszę dodać funkcję przesunięcia, ale nie wiem, gdzie ją zastosować lub czy jest lepszy sposób. Oto mój .draggable()kod inicjalizacyjny:

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

Masz jakiś pomysł, co mogę zrobić, aby to naprawić?

Alex
źródło
czy możesz dostarczyć działające demo
jimy
@jimy to wszystko jest dynamiczne i bardzo bezpieczne, więc musiałbym napisać zupełnie nowy przykład; Zrobię to, jeśli nikt nie ma szybkiej odpowiedzi jak najszybciej.
Alex
Czy możesz opublikować wszystkie właściwości CSS, które ma lub dziedziczy twój draggable?
DarthJDG
2
Według mojej odpowiedzi poniżej, wydaje się, że ostatecznie zostało to naprawione
Patrick,

Odpowiedzi:

107

To może być powiązany raport o błędzie, istnieje już od dłuższego czasu: http://bugs.jqueryui.com/ticket/3740

Wydaje się, że dzieje się to w każdej testowanej przeglądarce (Chrome, FF4, IE9). Istnieje kilka sposobów obejścia tego problemu:

1. Użyj position:absolute;w swoim css. Wydaje się, że nie ma to wpływu na elementy pozycjonowane absolutnie.

2. Upewnij się, że element nadrzędny (zdarzenie, jeśli jest treścią) został overflow:auto;ustawiony. Mój test wykazał, że to rozwiązanie naprawia pozycję, ale wyłącza funkcję automatycznego przewijania. Nadal możesz przewijać za pomocą kółka myszy lub klawiszy strzałek.

3. Zastosuj poprawkę sugerowaną w powyższym zgłoszeniu błędu ręcznie i dokładnie przetestuj, czy powoduje inne problemy.

4. Poczekaj na oficjalną poprawkę. Zaplanowano na jQuery UI 1.9, chociaż w przeszłości było to kilka razy odkładane.

5. Jeśli masz pewność, że dzieje się to w każdej przeglądarce, możesz umieścić te hacki w zdarzeniach draggables, których dotyczy ten problem, aby poprawić obliczenia. Do przetestowania jest jednak wiele różnych przeglądarek, więc należy go używać tylko w ostateczności:

$('.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;
   }
});
DarthJDG
źródło
12
To wspaniale, dziękuję! (Przepełnienie ustawień: automatycznie naprawiłem to natychmiast. Zastosowałem styl do poszczególnych komórek tabeli.
Alex
2
jsfiddle.net/a2hzt/5 overflow-y: przewijanie elementu html również stwarza ten problem w przeglądarce Firefox (działa Chrome), po prostu przewiń w dół i spróbuj przeciągnąć.
digitalPBK
8
To jest ba-a-ACK, dla helper: "clone". bugs.jqueryui.com/ticket/9315 Poziom bloker , wycięcie powyżej major. tj.vantoll mówi, że „6 możliwych do przeciągnięcia poprawek, które wylądowały w wersji 1.10.3, może być podejrzanych”. Najprostszy jak dotąd przykład: jsfiddle.net/7AxXE
Bob Stein
7
Potwierdzono, ten błąd występuje w interfejsie użytkownika jQuery 1.10.3, ale nie w wersji 1.10.2
Bob Stein
2
Wygląda na to, że problem występuje również w interfejsie użytkownika jQuery 1.10.4 . Na razie pozostanę przy 1.10.2 !
lhan
45

To rozwiązanie działa bez dostosowywania pozycji czegokolwiek, po prostu klonujesz element i ustawiasz go absolutnie.

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

Pomocnikiem może być funkcja, która musi zwrócić element DOM do przeciągnięcia.

mordy
źródło
+1 Dziękuję bardzo, to działa dla mnie z sortable (chciałem spróbować czegoś podobnego, ale mniej eleganckiego). Masz jednak małą literówkę z $ j! :)
Iain Collins,
4
Dla mnie: przeciąganie w ogóle nie działa z tym i zwraca błędy: TypeError: this.offsetParent [0] jest niezdefiniowane
ProblemsOfSumit
Myślę, że to ui.helper nie tylko ui
Mohammed Joraid
1
Dziękuję, pomóż mi z Sortable
BG BRUNO
1
To jedyna odpowiedź, która mi pasuje i jest najłatwiejsza do wdrożenia. Świetne rozwiązanie
Brett Gregson
11

To zadziałało dla mnie:

start: function (event, ui) {
   $(this).data("startingScrollTop",window.pageYOffset);
},
drag: function(event,ui){
   var st = parseInt($(this).data("startingScrollTop"));
   ui.position.top -= st;
},
Ashraf Fayad
źródło
napraw mój problem,"1.11.0"
Зелёный
To zabawne rozwiązanie, ale będzie działać tylko w przeglądarkach, które mają błąd (Chrome). Przeglądarki, które nie mają błędu, będą go teraz miały, ale odwrócone :)
manu
Uwaga: niektórzy parsery JS mogą narzekać na „brakujący radix” podczas korzystania z tego rozwiązania. Aby to naprawić, zamień var st = parseInt ($ (this) .data ("startScrollTop")); z var st = parseInt ($ (this) .data ("startScrollTop"), 10); (tj. podać system liczbowy, który ma być użyty). 10 jest wartością domyślną, ale niektóre parsery mogą mimo wszystko wymagać, aby była obecna (np. Webpack)
ripper17
7

Przepraszam za napisanie innej odpowiedzi. Ponieważ żadne z rozwiązań w powyższej odpowiedzi nie mogło być przeze mnie użyte, dużo googlowałem i wprowadziłem wiele frustrujących drobnych zmian, zanim znalazłem inne rozsądne rozwiązanie.

Wydaje się, że ten problem występuje, gdy którykolwiek z elementów nadrzędnych został positionustawiony jako „względny”. Musiałem przetasować moje znaczniki i zmienić CSS, ale usuwając tę ​​właściwość ze wszystkich rodziców, mogłem .sortable()działać poprawnie we wszystkich przeglądarkach.

Joshua Bambrick
źródło
To samo dla mnie tutaj. Każdy position: relative;rodzic powoduje to.
wojtiku
całkowicie agresywny! Dla mnie był to po prostu styl inline w ciele, z position: relative;którym trzeba było usunąć ... elementy nadrzędne między ciągnikiem a ciałem wydają się nie powodować tutaj problemów ..
con
1
o, to było to, dzięki, garrr, dlaczego ludzie nie używają Draguli w dzisiejszych czasach - dzięki!
Dominic
Dziękuję bardzo! Rodzic rodzica zajmującego stanowisko: krewny spowodował to dla mnie
wjk2a1
7

Wygląda na to, że ten błąd pojawia się bardzo często i za każdym razem jest inne rozwiązanie. Żadne z powyższych ani nic innego, co znalazłem w Internecie, nie działało. Używam jQuery 1.9.1 i Jquery UI 1.10.3. Oto jak to naprawiłem:

$(".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();
  }
});

Działa w FF, IE, Chrome, jeszcze nie testowałem tego w innych przeglądarkach.

kazmer
źródło
1
to zadziałało dla mnie, z wyjątkiem tego, że musiałem użyć ui.offset.top zamiast ui.position.top
c.dunlap
5

Usuwam przepełnienie:

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

I działa idealnie!

Miguel Puig
źródło
5

Ten błąd został przeniesiony na http://bugs.jqueryui.com/ticket/6817 i wydaje się, że około 5 dni temu (16 grudnia 2013 r. Lub później) został ostatecznie naprawiony. Sugeruje się teraz, aby użyć najnowszej kompilacji deweloperskiej z http://code.jquery.com/ui/jquery-ui-git.js lub poczekać na wersję 1.10.4, która powinna zawierać tę poprawkę .

Edycja: Wygląda na to, że ta poprawka może być teraz częścią http://bugs.jqueryui.com/ticket/9315, która ma zostać usunięta do wersji 1.11. Wydaje się, że użycie powyższej wersji jQuery, połączonej z kontrolą źródła, rozwiązuje problem dla mnie i @Scott Alexander (komentarz poniżej).

Patrick
źródło
Używam wersji 1.10.4 i błąd nadal istnieje, jednak użyłem tego linku i wszystko działa dobrze.
Scott Alexander
@ScottAlexander Poprawka mogła zostać dołączona do innego biletu niż myślałem. Na tej podstawie zredagowałem moją odpowiedź. Dzięki!
Patrick
4

Wydaje się niezwykłe, że ten błąd powinien zniknąć tak długo. Dla mnie jest to problem w Safari i Chrome (czyli przeglądarkach webkit), ale nie w IE7 / 8/9 ani w Firefoksie, które działają dobrze.

Zauważyłem, że ustawienie bezwzględne lub stałe, z lub bez! Ważne, nie pomogło, więc ostatecznie dodałem linię do mojej funkcji obsługi przeciągania:

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

Spodziewałem się, że będę musiał uczynić tę linię specyficzną dla zestawu internetowego, ale co ciekawe, wszędzie działała dobrze. (Wkrótce spodziewaj się ode mnie komentarza mówiącego „eee nie, w rzeczywistości zepsuło to wszystkie inne przeglądarki”).

Allen
źródło
1
To działa, ale kiedy przewijasz podczas przeciągania, nadal przesuwa pozycję y. Rozwiązanie numer 5 w DarthJDG działa również podczas przewijania podczas przeciągania.
mirelon,
3

co zrobiłem to:

$("#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);
         }
        });
Pankaj Sharma
źródło
1

Nie jestem do końca pewien, czy to zadziała w każdym przypadku, ale to obejście, które właśnie wykonałem dla mnie we wszystkich różnych sytuacjach, które musiałem przetestować (i gdzie poprzednie proponowane rozwiązania podane tutaj i gdzie indziej zawiodły)

(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));

(Przesłałem to do modułu śledzącego jQuery.ui, aby zobaczyć, co o tym sądzą ... byłoby fajnie, gdyby ten 4-letni błąd mógł zostać w końcu poprawiony: /)

vor
źródło
1

Używam przeciągania JQuery w przeglądarce Firefox 21.0 i mam ten sam problem. Kursor pozostaje cal nad obrazem pomocniczym. Myślę, że jest to problem w samym Jquery, który wciąż nie został rozwiązany. Znalazłem obejście tego problemu, które polega na użyciu właściwości „cursorAt” elementu draggable. Użyłem go w następujący sposób, ale można to zmienić zgodnie z jego wymaganiami.

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

Uwaga: będzie to miało zastosowanie do wszystkich przeglądarek, więc po użyciu tego kodu sprawdź swoją stronę we wszystkich przeglądarkach, aby uzyskać prawidłowe lewe i górne pozycje.

impiyush
źródło
1

To właśnie zadziałało u mnie, po dostosowaniu wszystkiego, co przeczytałem na temat problemu.

$(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 jest rodzicem lub przodkiem z przepełnieniem: auto;

Wylicza pozycję przewijanego elementu i dodaje do pozycji pomocnika za każdym razem, gdy jest on przesuwany / przeciągany.

Mam nadzieję, że to komuś pomoże, ponieważ zmarnowałem na to więcej czasu.

Rnubi
źródło
1

Wydaje się, że rozwiązuje to problem bez konieczności używania pozycji: bezwzględna w rodzicu :)

$("body").draggable({
     drag: function(event, ui) { 
         return false; 
     } 
});
TomCe
źródło
Dzięki! to jedyna rzecz, która działała dla mnie. (Nie jestem pewien, czy rozumiem problem ... moim problemem jest to, że przeciąganie, przeciąganie przewijanie działa dobrze, gdy przeciąganie zaczyna się od paska przewijania u góry. Jeśli pasek przewijania zaczyna się niżej, pojawia się problem z przesunięciem)
John Smith
1

Udało mi się rozwiązać ten sam problem z dodawaniem display: inline-block do przeciągniętych elementów

Dodawanie position: relativeNIE zadziałało dla mnie (jQuery nadpisuje to przy position: absolutedrag start)

Używane wersje jQuery:

  • jQuery - 1.7.2
  • jQuery UI - 1.11.4
Plamen
źródło
position: relativemogło zadziałać, jeśli przeniesiesz go do elementu kontenera wyższego poziomu. Wiem, że teraz to nie pomaga, ale tylko w celach informacyjnych i może dla przyszłego, niespokojnego programisty.
gdibble
1

Miałem ten sam problem i stwierdziłem, że wszystko to było spowodowane klasą bootstrap "navbar-fixed-top" z pozycją do ustalonej, która przesuwała się w dół o <body>60px niżej niż na <html>górze. Kiedy więc przesuwałem w witrynie formularze, które można przeciągać, na górze formularza pojawił się kursor 60 pikseli.

Możesz zobaczyć, że w narzędziu do debugowania Chrome, w interfejsie Elements, kliknij <body>tag, a zobaczysz lukę między górą a treścią.

Ponieważ używam tego paska nawigacyjnego we wszystkich moich aplikacjach i nie chciałem modyfikować wywołania inicjującego do przeciągania (zgodnie z procedurą DarthJDG) dla każdego formularza. Zdecydowałem się w ten sposób rozszerzyć widżet draggable i po prostu dodać yOffset do mojej inicjalizacji draggable.

(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);

Teraz, kiedy inicjalizuję przeciągany element / formularz w witrynie za pomocą paska nawigacyjnego bootstrap:

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

Oczywiście będziesz musiał poeksperymentować, aby określić właściwy yOffset zgodnie z własną witryną.

W każdym razie dziękuję DarthJDG, który wskazał mi właściwy kierunek. Twoje zdrowie!

uciekł
źródło
0

Porzuciłem używanie draggable jQueryUi i przeniosłem się do lepszej wtyczki o nazwie jquery.even.drag , o znacznie mniejszym rozmiarze kodu, bez wszystkich bzdur, jakie ma jQueryUI.

Zrobiłem stronę demonstracyjną za pomocą tej wtyczki wewnątrz kontenera, który ma pozycję: naprawiono

Próbny

Mam nadzieję, że to komuś pomoże, ponieważ ten problem jest DUŻY.

vsync
źródło
0

Miałem podobny problem, tylko z konkretnym IE 10 działającym na Windows 8. Wszystkie inne przeglądarki działały dobrze. Usunięcie kursoraAt: {top: 0} rozwiązało problem.

nmm
źródło
0

Wypróbowałem tutaj różne odpowiedzi, w tym aktualizację jQuery i stwierdziłem, że to zadziałało. Przetestowałem to na najnowszym Chrome i IE. Myślę, że będzie to problem z różnymi rozwiązaniami w zależności od układu interfejsu użytkownika.

$('{selector}').draggable({
    start: function(event, ui) {
        ui.position.top -= $(document).scrollTop();
    },
    drag: function(event, ui) {
        ui.position.top -= $(document).scrollTop();
    }
});
Lee Willis
źródło
0

Dlaczego nie zająć pozycji kursora? Używam sortowalnej wtyczki i naprawiam to tym kodem:

sort: function(e, ui) {
    $(".ui-sortable-handle.ui-sortable-helper").css({'top':e.pageY});
}
Aztrozero
źródło
0

Użyj appendTo: "body'i ustaw pozycję za pomocą cursorAt. U mnie to działa dobrze.

Przykład mojej ikony podążającej za kursorem myszy nawet po przewinięciu strony

$('.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'
Michelle Diniz
źródło
0

Używam lepkiej nawigacji na górze i pomyślałem, że to właśnie powoduje problem z przewijaniem, który wszyscy wydają się mieć. Wypróbowałem pomysł wszystkich innych za pomocą kursora, próbowałem powstrzymać i nic nie działało Z WYJĄTKIEM zakłócenia przepełnienia HTML w CSS! Niesamowite, jak mały CSS wszystko schrzani. Oto, co zrobiłem i działa jak urok:

html {
  overflow-x: unset;
}

body {
  overflow-x: hidden;
}
Altus Nix
źródło