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ć?


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

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.


+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;
},

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.


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.


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!


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).


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”).


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

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: /)


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.


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.


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

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

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!


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.


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.


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

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

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'

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;
}
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.