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

72

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

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

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

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

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

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

  • 0
    Можете ли вы предоставить рабочую демонстрацию?
  • 0
    @jimy это все динамично и очень безопасно, поэтому мне придется написать совершенно новый пример; Я сделаю, если ни у кого нет быстрого ответа как можно скорее.
Показать ещё 2 комментария
Теги:
jquery-ui-draggable
draggable

19 ответов

99
Лучший ответ

Это может быть связанный отчет об ошибке, это было довольно давно: 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
    Это здорово, спасибо! (Переполнение настроек: автоматическое исправление сразу. Я применил стиль к отдельным ячейкам таблицы.
  • 1
    Я обнаружил, что ошибка также происходит, если ваш исходный перетаскиваемый объект является дочерним элементом позиции: фиксированный элемент. Единственное, что сработало для меня, это переместить клон из фиксированного элемента - start: function (event, ui) {ui.helper.appendTo ($ ('body')); } - и примените патч в отчете об ошибке. НТН
Показать ещё 22 комментария
38

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

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

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

  • 0
    +1 Большое спасибо, это работает для меня с сортируемым (я собирался попробовать что-то похожее, но менее элегантное). У вас маленькая опечатка с $ j! :)
  • 4
    Для меня: перетаскивание не работает вообще с этим и возвращает ошибки: TypeError: this.offsetParent [0] не определено
Показать ещё 6 комментариев
10

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

start: function (event, ui) {
   $(this).data("startingScrollTop",window.pageYOffset);
},
drag: function(event,ui){
   var st = parseInt($(this).data("startingScrollTop"));
   ui.position.top -= st;
},
  • 0
    Это решение отлично сработало для меня. Спасибо!
  • 0
    Работал хорошо! ти
Показать ещё 4 комментария
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
5

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

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

  • 0
    Я использую 1.10.4, и ошибка все еще там, хотя я использовал эту ссылку, и все работает хорошо.
  • 0
    @ScottAlexander Исправление может быть связано с другим билетом, чем я думал. Я отредактировал свой ответ на основе этого. Спасибо!
5

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

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

  • 0
    То же самое для меня здесь. Любая position: relative; у любого родителя это происходит.
  • 0
    совершенно согласен! Для меня это был просто встроенный стиль тела с position: relative; который должен был быть удален .. родительские элементы между draggable и телом, кажется, не создают проблем здесь ..
Показать ещё 2 комментария
4

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

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

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

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

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

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

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

Я ожидал, что вам понадобится сделать эту строку для веб-сайта, но, с любопытством, она отлично работала везде. (Ожидайте, что комментарий от меня скоро скажет: "нет, на самом деле это перепутало все другие браузеры".)

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

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

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

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

  • jQuery - 1.7.2
  • jQuery UI - 1.11.4
  • 0
    position: relative возможно, сработал, если вы переместили его в контейнерный элемент более высокого уровня. Я знаю, что это не помогает сейчас, но только для справки и, возможно, для будущего проблемного разработчика.
1

Это похоже на обходное решение без необходимости использования позиции: absolute в родительском:)

$("body").draggable({
     drag: function(event, ui) { 
         return false; 
     } 
});
  • 0
    Спасибо! это единственное, что сработало для меня. (Я не уверен, что понимаю проблему .. моя проблема в том, что перетаскивание, перетаскивание прокрутки работает нормально, когда перетаскивание начинается с полосы прокрутки вверху. Если полоса прокрутки начинается ниже, я получаю проблему смещения)
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

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

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

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

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

0

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

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

Так как я использую эту навигационную панель по всем моим приложениям и не хочу изменять мой инициализирующий вызов для перетаскивания (в соответствии с процедурой DarthJDG) для каждой формы. Я решил расширить draggable widget таким образом и просто добавить 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);

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

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

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

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

0

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

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

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

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

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

0

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

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

Demo

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

Ещё вопросы

Сообщество Overcoder
Наверх
Меню