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


79

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

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

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

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

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

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



@jimy все динамично и очень безопасно, поэтому мне пришлось бы написать совершенно новый пример; Я сделаю это, если ни у кого не будет быстрого ответа как можно скорее.
Alex

Можете ли вы опубликовать все свойства css, которые ваш перетаскиваемый объект имеет или наследует?
DarthJDG

2
Согласно моему ответу далеко ниже, это, кажется, наконец-то исправлено
Патрик

Ответы:


107

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

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

1. Используйте position:absolute;в своем css. Абсолютно позиционированные элементы не пострадали.

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

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

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

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

$('.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
Здорово, спасибо! (Переполнение настроек: автоматически исправлено немедленно. Я применил стиль к отдельным ячейкам таблицы.
Alex

2
jsfiddle.net/a2hzt/5 overflow-y: прокрутка элемента html также создает эту проблему в firefox (Chrome работает), просто прокрутите вниз и попробуйте перетащить.
digitalPBK 01

8
Это ба-а-а, потому что helper: "clone". bugs.jqueryui.com/ticket/9315 Уровень блокатор , вырезка выше основных. tj.vantoll говорит: «6 перетаскиваемых исправлений, появившихся в 1.10.3, могут быть подозрительными». Самый простой
Боб Штейн

7
Подтверждено, что эта ошибка присутствует в jQuery UI 1.10.3, но не в 1.10.2
Боб Стейн,

2
Похоже, проблема существует и в jQuery UI 1.10.4 . Я пока просто буду придерживаться 1.10.2 !
lhan

45

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

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

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


+1 Большое спасибо, у меня это работает с sortable (я собирался попробовать что-то похожее, но менее элегантное). Однако у вас есть небольшая опечатка с $ j! :)
Иэн Коллинз

4
Для меня: перетаскивание вообще не работает с этим и возвращает ошибки: TypeError: this.offsetParent [0] не определено
ProblemsOfSumit

Я думаю, что это ui.helper not only ui
Мохаммед Джораид

1
Спасибо, что помогли мне с Sortable
BG BRUNO

1
Это единственный ответ, который мне подходит, и его проще всего реализовать. Отличное решение
Бретт Грегсон

11

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

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

исправь мою проблему,"1.11.0"
Зелёный

Это забавное решение, но оно будет работать только в браузерах, в которых есть ошибка (Chrome). Браузеры, в которых нет ошибки, теперь будут иметь ее, но в инвертированном виде :)
ману

Примечание: некоторые JS-парсеры могут жаловаться на «отсутствие системы счисления» при использовании этого решения. Чтобы исправить это, замените var st = parseInt ($ (this) .data ("startScrollTop")); с var st = parseInt ($ (this) .data ("startScrollTop"), 10); (т.е. укажите используемую систему счисления). 10 - значение по умолчанию, но некоторые парсеры могут требовать его наличия (например, webpack)
ripper17

7

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

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


То же самое и здесь. Это происходит position: relative;в любом родительском элементе.
wojtiku

полностью согласен! Для меня это был просто встроенный стиль в теле, с position: relative;которым пришлось удалить ... родительские элементы между перетаскиваемым и телом, похоже, не создают здесь проблем ..
con

1
Боже мой, спасибо, гаррр, почему люди не используют Драгулу в наши дни - спасибо!
Доминик

Спасибо огромное! Родитель или родитель, имеющий позицию: родственник вызвал это для меня
wjk2a1

7

Похоже, что эта ошибка возникает очень часто, и каждый раз появляется новое решение. Ничего из вышеперечисленного или что-то еще, что я нашел в Интернете, не помогло. Я использую 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, в других браузерах еще не тестировал.


1
это сработало для меня, за исключением того, что мне пришлось использовать ui.offset.top вместо ui.position.top
c.dunlap


5

Эта ошибка была перенесена на 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 (комментарий ниже).


Я использую 1.10.4, и ошибка все еще существует, хотя использовал эту ссылку, и все работает хорошо.
Скотт Александр

@ScottAlexander Исправление могло быть прикреплено к другому билету, чем я думал. Я отредактировал свой ответ на основании этого. Благодаря!
Патрик

4

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

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

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

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


1
Это работает, но когда вы прокручиваете при перетаскивании, он все равно смещает позицию y. Решение № 5 от DarthJDG работает также при прокрутке при перетаскивании.
mirelon 06

3

я сделал следующее:

$("#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

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

(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, чтобы узнать, что они думают об этом ... было бы круто, если бы эту ошибку четырехлетней давности можно было наконец исправить: /)


1

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

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

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


1

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

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

Определяет положение элемента прокрутки и добавляет к положению помощника при каждом его перемещении / перетаскивании.

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


1

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

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

Благодаря! это единственное, что у меня сработало. (Я не уверен, что понимаю проблему. Моя проблема в том, что перетаскивание, перетаскивание прокрутки работают нормально, когда перетаскивание начинается с полосы прокрутки вверху. Если полоса прокрутки начинается ниже, у меня возникает проблема смещения)
Джон Смит

1

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

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

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

  • jQuery - 1.7.2
  • jQuery UI - 1.11.4

position: relativeмогло сработать, если вы переместили его в элемент контейнера более высокого уровня. Я знаю, что сейчас это не помогает, но только для справки и, возможно, для будущего проблемного разработчика.
gdibble

1

У меня была та же проблема, и я обнаружил, что все это произошло из-за класса «navbar-fixed-top» панели навигации начальной загрузки с фиксированным положением, который перемещается на <body>60 пикселей ниже, чем<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, который указал мне правильное направление. Ура!


0

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

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

Демо

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


0

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


0

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

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

0

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

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

0

Используйте 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'

0

Я использую липкую навигацию вверху и думал, что это было причиной проблемы с прокруткой, которая, похоже, есть у всех остальных. Я попробовал идею других с cursorAt, я попробовал сдерживание, и ничего не сработало, ЗА ИСКЛЮЧЕНИЕМ отключения моего переполнения html в CSS! Безумие, как немного CSS все испортит. Это то, что я сделал, и это работает как шарм:

html {
  overflow-x: unset;
}

body {
  overflow-x: hidden;
}
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.