jQuery draggable показывает помощника в неправильном месте после прокрутки страницы

Я использую jQuery draggable и удаляемый для системы планирования работы, которую я разрабатываю. Пользователи перетаскивают задания на другой день или пользователя, а затем данные обновляются с помощью вызова ajax.

Все работает нормально, за исключением случаев, когда я прокручиваю главную страницу вниз (вакансии появляются в большом недельном планировщике, который превышает нижнюю часть окна моего браузера). Если я попытаюсь перетащить сюда перетаскиваемый элемент, он появится над моим курсором мыши на такое же количество пикселей, как я прокрутил вниз. Состояние наведения по-прежнему работает нормально, и функциональность работает, но выглядит неправильно.

Я использую jQuery 1.6.0 и jQuery UI 1.8.12.

Я уверен, что мне нужно добавить функцию смещения, но я не знаю, где ее применить или есть ли лучший способ. Вот мой код инициализации .draggable():

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

Любая идея, что я могу сделать, чтобы исправить это?


person Alex    schedule 26.04.2011    source источник
comment
Можете ли вы предоставить некоторые рабочие демо   -  person jimy    schedule 26.04.2011
comment
@jimy это все динамично и очень безопасно, поэтому мне придется написать совершенно новый пример; Я сделаю, если ни у кого нет быстрого ответа как можно скорее.   -  person Alex    schedule 26.04.2011
comment
Можете ли вы опубликовать все свойства CSS, которые имеет или наследует ваш перетаскиваемый объект?   -  person DarthJDG    schedule 26.04.2011
comment
Судя по моему ответу ниже, это окончательно исправлено   -  person Patrick    schedule 22.12.2013


Ответы (21)


Это может быть связанный отчет об ошибке, он существует уже довольно давно: http://bugs.jqueryui.com/ticket/3740< /а>

Кажется, это происходит в каждом браузере, который я тестировал (Chrome, FF4, IE9). Есть несколько способов обойти эту проблему:

1. Используйте position:absolute; в CSS. Абсолютно позиционированные элементы, похоже, не затрагиваются.

2. Убедитесь, что родительский элемент (событие, если это тело) имеет значение overflow:auto;. Мой тест показал, что это решение фиксирует положение, но отключает функцию автопрокрутки. Вы по-прежнему можете прокручивать с помощью колесика мыши или клавиш со стрелками.

3. Примените исправление, предложенное в приведенном выше отчете об ошибке, вручную и тщательно проверьте, не вызывает ли оно других проблем.

4. Дождитесь официального исправления. Он запланирован на jQuery UI 1.9, хотя в прошлом его несколько раз откладывали.

5. Если вы уверены, что это происходит в каждом браузере, вы можете поместить эти хаки в соответствующие события draggables, чтобы исправить вычисления. Тем не менее, нужно протестировать множество разных браузеров, поэтому его следует использовать только в крайнем случае:

$('.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;
   }
});
person DarthJDG    schedule 26.04.2011
comment
Это здорово, спасибо! (Settings overflow:auto сразу исправил. Я применил стиль к отдельным ячейкам таблицы. - person Alex; 28.04.2011
comment
Я обнаружил, что ошибка также возникает, если ваш исходный перетаскиваемый объект является дочерним элементом позиции: фиксированный элемент. Единственное, что сработало для меня, это переместить клон из фиксированного элемента -- start: function(event,ui) { ui.helper.appendTo($('body')); } -- и примените патч в отчете об ошибке. чт - person Altreus; 18.05.2011
comment
jsfiddle.net/a2hzt/5 overflow-y: прокрутка элемента html также создает эту проблему на Firefox (хром работает), просто прокрутите вниз и попробуйте перетащить. - person digitalPBK; 01.06.2012
comment
Ответ @Josh 'Bambi' Bambrick также, кажется, помогает. Таким образом, удаление position: relative; из всех родителей также является хорошим решением. - person wojtiku; 17.04.2013
comment
Вариант последнего средства ПОЧТИ работал для меня, за исключением того, что прокручиваемые мной элементы div не находились в родительском слое (их было несколько вверх), поэтому я определил их с помощью селектора. Кроме того, по какой-то причине ваш код имеет -= в установщике ui.position, а не +=, что и исправило мою ситуацию. Если кто-то еще застрял на этом, попробуйте (в функции перетаскивания): drag: function(event,ui){ var st = parseInt($(this).data("startingScrollTop")); ui.position.top += $("#parent-div-selector").scrollTop() - st; } - person Calciphus; 13.06.2013
comment
это сводит меня с ума. У меня есть горизонтальная прокрутка (простой слайдер с перетаскиваемыми элементами внутри слайдов), и их позиционирование сумасшедшее. Пока ни одно решение не помогло :-/ - person ProblemsOfSumit; 19.07.2013
comment
хорошо, я понял свою проблему: решение состояло в том, чтобы удалить опцию сдерживания! Я искал часами! - person ProblemsOfSumit; 19.07.2013
comment
Это ба-ак, для helper: "clone". bugs.jqueryui.com/ticket/9315 Уровень блокировщик, a ступень выше мажора. tj.vantoll говорит, что 6 перетаскиваемых исправлений, появившихся в 1.10.3, могут вызывать подозрения. Самый простой пример: jsfiddle.net/7AxXE - person Bob Stein; 29.07.2013
comment
Подтверждено, эта ошибка есть в jQuery UI 1.10.3, но не в 1.10.2. - person Bob Stein; 29.07.2013
comment
По какой-то причине переполнение или позиция у меня не сработали. Но изменения в исходном коде сделали. Но откат к 1.10.2 показался нам более подходящим решением для нашего проекта. - person He Nrik; 21.10.2013
comment
Похоже, проблема существует и в jQuery UI 1.10.4. Пока я просто придерживаюсь 1.10.2! - person lhan; 26.03.2014
comment
"1.11.0" ошибка все еще здесь. - person Зелёный; 21.09.2014
comment
похоже, что ошибка все еще существует и в 1.11.2. - person Victor; 03.12.2014
comment
Моя проблема в том, что мне приходится работать с таблицей длинных списков, в ней есть элементы прокрутки и перетаскивания. Эта ошибка еще в 1.11.2. Любое предложение для этого. Я пробовал все решения, которые я нашел, но все еще не могу это исправить. Вот jsfiddle - person thanh; 06.12.2014
comment
Для меня ошибка исправлена ​​при использовании 1.11.2 (я пришел с 1.10.4). - person Lode; 16.01.2015
comment
ломал голову над этим точным вопросом, и overflow:auto; полностью сработал для меня, спасибо, чувак. - person Cesar Bielich; 23.04.2015
comment
Для меня этой ошибки не было с 1.10.4, но она снова появилась с версией 1.11.2. overflow:auto или overflow:hidden — хорошие обходные пути. Я не знаю, как повторно открыть ошибку для команды jQueryUI. - person Fabien Quatravaux; 23.04.2015
comment
Пункт 1) вводит в заблуждение. На самом деле речь идет не об абсолютном позиционировании элементов, а о том, чтобы их контейнер имел указанную позицию (абсолютную или относительную). Я исправил эту проблему, установив position:relative в контейнере, потому что вспомогательный элемент ранее был абсолютно расположен во внешнем контейнере. - person andrea.spot.; 28.04.2015
comment
Спасибо за этот ответ, у меня было все, кроме overflow: auto, и это решение исправило мои ошибки. - person Shawn V; 25.06.2015
comment
@DartJDG, могу я попросить вас взглянуть на вопрос, связанный с перетаскиванием, здесь: stackoverflow.com/questions/54498364/ - person Istiaque Ahmed; 03.02.2019
comment
Вау! Я потратил целый день, пытаясь найти обходной путь, но простое переполнение: auto; сделал трюк! Самая большая благодарность тебе :D - person Konstantin; 22.07.2019

Это решение работает без настройки позиционирования чего-либо, вы просто клонируете элемент и делаете его абсолютно позиционированным.

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

Помощником может быть функция, которая должна возвращать элемент DOM для перетаскивания.

person mordy    schedule 28.09.2012
comment
+1 Большое спасибо, у меня это работает с сортировкой (я собирался попробовать что-то подобное, но менее элегантно). У вас небольшая опечатка с $j! :) - person Iain Collins; 21.12.2012
comment
Для меня: перетаскивание с этим вообще не работает и возвращает ошибки: TypeError: this.offsetParent[0] is undefined - person ProblemsOfSumit; 19.07.2013
comment
Я думаю, что это ui.helper не только ui - person Mohammed Joraid; 18.07.2014
comment
Спасибо, помогите мне с Sortable - person BG BRUNO; 01.12.2014
comment
После того, как я проголосовал за это как за одно из менее хакерских решений, я понял, что проблема для меня заключалась в том, что у родителя был position: relative, как обнаружил @Josh Bambrick. - person Dominic; 10.11.2015
comment
идеальное исправление при использовании position: relative; абсолютно необходимо. +1 - person Barry Chapman; 13.07.2016
comment
Это единственный ответ, который работает для меня, и его проще всего реализовать. Отличное решение - person Brett Gregson; 19.09.2017
comment
следующее добавление добавит ощущения при перетаскивании $(ui).css({ 'opacity': '0.1' }); (добавьте после клонирования) - person Vidmantas Norkus; 17.01.2019

Это сработало для меня:

start: function (event, ui) {
   $(this).data("startingScrollTop",window.pageYOffset);
},
drag: function(event,ui){
   var st = parseInt($(this).data("startingScrollTop"));
   ui.position.top -= st;
},
person Ashraf Fayad    schedule 24.01.2014
comment
решите мою проблему, "1.11.0" - person Зелёный; 21.09.2014
comment
Это забавное решение, но оно будет работать только в браузерах, в которых есть ошибка (Chrome). Браузеры, в которых нет этой ошибки, теперь будут иметь ее, но перевернутую :) - person manu; 04.06.2015
comment
Примечание. Некоторые JS-парсеры могут жаловаться на отсутствие системы счисления при использовании этого решения. Чтобы исправить, замените var st = parseInt($(this).data(startingScrollTop)); с var st = parseInt($(this).data(startingScrollTop), 10); (т.е. укажите используемую систему счисления). 10 — значение по умолчанию, но некоторые парсеры могут потребовать, чтобы это присутствовало (например, веб-пакет). - person ripper17; 06.03.2018

Извините, что написал другой ответ. Поскольку ни одно из решений в приведенном выше ответе не могло быть использовано мной, я много гуглил и внес много разочаровывающих незначительных правок, прежде чем нашел другое разумное решение.

Эта проблема возникает всякий раз, когда для любого родительского элемента position установлено значение "относительно". Мне пришлось перетасовать мою разметку и изменить мой CSS, но, удалив это свойство у всех родителей, я смог заставить .sortable() работать правильно во всех браузерах.

person Joshua Bambrick    schedule 13.07.2012
comment
То же самое для меня здесь. Любой position: relative; в любом родителе вызывает это. - person wojtiku; 17.04.2013
comment
полностью согласен! Для меня это был просто встроенный стиль в теле с position: relative;, который нужно было удалить. Родительские элементы между перетаскиваемым и телом, похоже, не создают здесь проблем. - person con; 08.09.2013
comment
омг, спасибо, гаррр, почему люди не используют Драгулу в наше время - спасибо! - person Dominic; 10.11.2015
comment
Большое спасибо! Родитель родителя с положением: родственник вызвал это для меня - person wjk2a1; 26.01.2018

Похоже, эта ошибка возникает очень часто, и каждый раз находится другое решение. Ничего из вышеперечисленного или что-либо еще, что я нашел в Интернете, не работало. Я использую jQuery 1.9.1 и JQuery UI 1.10.3. Вот как я это исправил:

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

Работает в FF, IE, Chrome, в других браузерах пока не проверял.

person kazmer    schedule 04.06.2013
comment
это сработало для меня, за исключением того, что мне пришлось использовать ui.offset.top вместо ui.position.top - person c.dunlap; 03.10.2014

Я удаляю переполнение:

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

И это работает отлично!

person Miguel Puig    schedule 27.09.2012

Эта ошибка была перенесена на http://bugs.jqueryui.com/ticket/6817 и, как примерно 5 дней назад (16 декабря 2013 г. или около того), по-видимому, окончательно исправлено. Прямо сейчас предлагается использовать последнюю сборку разработки с http://code.jquery.com/ui/jquery-ui-git.js или дождитесь версии 1.10.4, которая должна содержать это исправление.

Изменить: кажется, что это исправление теперь может быть частью http://bugs.jqueryui.com/ticket/9315, выпуск которого не планируется до версии 1.11. Использование приведенной выше версии jQuery для управления исходным кодом, похоже, решает проблему для меня и @Scott Alexander (комментарий ниже).

person Patrick    schedule 22.12.2013
comment
Я использую 1.10.4, и ошибка все еще существует, хотя я использовал эту ссылку, и все работает хорошо. - person Scott Alexander; 28.01.2014
comment
@ScottAlexander Исправление могло быть привязано к другому билету, чем я думал. Я отредактировал свой ответ на основе этого. Спасибо! - person Patrick; 28.01.2014

Кажется замечательным, что эта ошибка так долго оставалась неисправленной. Для меня это проблема в Safari и Chrome (то есть в браузерах webkit), но не в IE7/8/9 и не в Firefox, которые все работают нормально.

Я обнаружил, что установка абсолютного или фиксированного значения, с !important или без него, не помогает, поэтому в конце концов я добавил строку в свою функцию обработчика перетаскивания:

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

Я ожидал, что мне нужно будет сделать эту строку специфичной для webkit, но, как ни странно, она везде работала нормально. (Ожидайте вскоре комментарий от меня, говорящий: «Эээ, нет, на самом деле это испортило все остальные браузеры».)

person Allen    schedule 15.08.2012
comment
Это работает, но при прокрутке во время перетаскивания положение y все равно смещается. Решение DarthJDG № 5 работает также при прокрутке во время перетаскивания. - person mirelon; 06.03.2013

что я сделал это:

$("#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);
         }
        });
person Pankaj Sharma    schedule 13.04.2014

Я не совсем уверен, что это будет работать в каждом случае, но этот обходной путь, который я только что сработал для меня во всех различных ситуациях, которые мне приходилось тестировать (и где все предыдущие предложенные решения, приведенные здесь и в других местах, не сработали)

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

(Я отправил его на трекер jQuery.ui, чтобы узнать, что они об этом думают.

person vor    schedule 26.07.2012

Я использую JQuery draggable в Firefox 21.0, и у меня такая же проблема. Курсор остается на дюйм выше вспомогательного изображения. Я думаю, что это проблема самого Jquery, которая до сих пор не решена. Я нашел обходной путь для этой проблемы, который использует свойство «cursorAt» перетаскиваемого объекта. Я использовал его следующим образом, но его можно изменить в соответствии с его требованиями.

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

Примечание. Это применимо для всех браузеров, поэтому после использования этого кода проверьте свою страницу во всех браузерах, чтобы получить правильные позиции слева и сверху.

person impiyush    schedule 18.06.2013

Это то, что сработало для меня после адаптации всего, что я прочитал по этой проблеме.

$(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 является родителем или предком с overflow:auto;

Вычисляет положение элемента прокрутки и добавляет к положению помощника каждый раз, когда он перемещается/перетаскивается.

Надеюсь, это поможет кому-то, так как я потратил на это много времени.

person Rnubi    schedule 01.07.2013

Кажется, это обходной путь без необходимости использовать position:absolute в родительском элементе :)

$("body").draggable({
     drag: function(event, ui) { 
         return false; 
     } 
});
person TomCe    schedule 01.02.2014
comment
Спасибо! это единственное, что сработало для меня. (Я не уверен, что понимаю проблему. Моя проблема в том, что перетаскивание, перетаскивание и прокрутка работают нормально, когда перетаскивание начинается с полосы прокрутки вверху. Если полоса прокрутки начинается ниже, я получаю проблему со смещением) - person John Smith; 11.07.2014

Мне удалось решить ту же проблему с добавлением display: inline-block к перетаскиваемым элементам.

Добавление position: relative у меня НЕ сработало (jQuery переопределяет его с помощью position: absolute при запуске перетаскивания)

Используемые версии jQuery:

  • jQuery — 1.7.2
  • Пользовательский интерфейс jQuery — 1.11.4
person Plamen    schedule 30.04.2016
comment
position: relative мог бы работать, если бы вы переместили его в элемент контейнера более высокого уровня. Я знаю, что это не помогает сейчас, но просто для справки и, возможно, для будущего проблемного разработчика. - person gdibble; 23.08.2016

У меня была та же проблема, и я обнаружил, что все это было из-за класса навигационной панели начальной загрузки «navbar-fixed-top» с фиксированной позицией, который опускался на мои <body> 60px ниже, чем <html> сверху. Поэтому, когда я перемещал перетаскиваемые формы на своем сайте, курсор появлялся на 60 пикселей поверх формы.

Вы можете видеть, что в инструменте отладки Chrome в интерфейсе Elements щелкните тег <body>, и вы увидите зазор между верхом и телом.

Поскольку я использую эту панель навигации во всех своих приложениях и не хочу изменять свой инициализирующий вызов для перетаскивания (согласно процедуре DarthJDG) для каждой формы. Я решил таким образом расширить перетаскиваемый виджет и просто добавить yOffset в мою перетаскиваемую инициализацию.

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

Теперь, когда я инициализирую перетаскиваемый элемент/форму на сайте с помощью панели навигации начальной загрузки:

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

Конечно, вам придется поэкспериментировать, чтобы определить правильное значение yOffset для вашего сайта.

В любом случае спасибо DarthJDG, который указал мне правильное направление. Ваше здоровье!

person fled    schedule 22.04.2017

Я перестал использовать jQueryUi draggable и перешел на использование лучшего плагина под названием jquery.even.drag, который намного меньше. размер кода, без всего дерьма jQueryUI.

Я сделал демо-страницу, используя этот плагин внутри контейнера с position:fixed

Демо

Надеюсь, это поможет кому-то, потому что эта проблема БОЛЬШАЯ.

person vsync    schedule 09.11.2012

У меня была аналогичная проблема, только с определенным IE 10, работающим в Windows 8. Все остальные браузеры работали нормально. Удаление cursorAt: {top: 0} решило проблему.

person nmm    schedule 16.01.2014

Я пробовал здесь разные ответы, включая обновление jQuery, и обнаружил, что это сработало для меня. Я тестировал это на последних версиях Chrome и IE. Я предполагаю, что это будет проблема с различными решениями в зависимости от вашего макета пользовательского интерфейса.

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

Почему бы не взять позицию курсора? я использую сортируемый плагин и исправляю его с помощью этого кода:

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

Используйте appendTo: "body' и установите положение с помощью cursorAt. Это прекрасно работает со мной.

Пример моего значка, следующего за курсором мыши даже после прокрутки страницы

$('.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'
person Michelle Diniz    schedule 11.04.2019

Я использую липкую навигацию вверху и подумал, что это вызывает проблему с прокруткой, которая, кажется, возникает у всех остальных. Я попробовал идею всех остальных с помощью cursorAt, я попробовал сдерживание, и ничего не сработало, КРОМЕ отключения моего переполнения html в CSS! Безумие, как немного CSS все испортит. Это то, что я сделал, и это работает как шарм:

html {
  overflow-x: unset;
}

body {
  overflow-x: hidden;
}
person Altus Nix    schedule 20.05.2019