it-swarm.com.ru

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

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

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

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

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

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

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

78
Alex

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

Похоже, это происходит в каждом браузере, который я тестировал (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;
   }
});
103
DarthJDG

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

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

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

43
mordy

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

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

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

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

7
Joshua Bambrick

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

7
kazmer

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

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

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

5
Miguel Puig

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

5
Patrick

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

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

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

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

4
Allen

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

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

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

Вы можете видеть, что в инструменте отладки 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);

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

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

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

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

1
fled

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

(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-летняя ошибка была наконец исправлена: /)

1
vor

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

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

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

  • jQuery - 1.7.2
  • пользовательский интерфейс jQuery - 1.11.4
1
Plamen

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

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

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

$(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
Rnubi

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

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

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

1
impiyush

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

html {
  overflow-x: unset;
}

body {
  overflow-x: hidden;
}
0
Altus Nix

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

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

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

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

Demo

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

0
vsync

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

Example of my icon following the mouse cursor even after scrolling the page

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

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

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

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

0
nmm