jQuery перетягує показує помічника в неправильному місці після прокрутки сторінки


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

@jimy це все динамічно і дуже безпечно, тому мені довелося б написати абсолютно новий приклад; Я зроблю це, якщо ні в кого не буде швидкої відповіді якомога швидше.
Олексій

Чи можете ви опублікувати всі властивості 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
Це чудово, дякую! (Переповнення налаштувань: автоматично виправлено негайно. Я застосував стиль до окремих комірок таблиці.
Олексій,

2
jsfiddle.net/a2hzt/5 overflow-y: прокрутка елемента html також створює цю проблему у firefox (chrome працює), просто прокрутіть вниз і спробуйте перетягнути.
digitalPBK

8
Це непросто, бо helper: "clone". bugs.jqueryui.com/ticket/9315 Блокувальник рівня , на відрізок вище основного. tj.vantoll говорить: "6 витяжних виправлень, які потрапили в 1.10.3, можуть бути підозрілими". Найпростіший приклад: jsfiddle.net/7AxXE
Боб Штейн

7
Підтверджено, ця помилка знаходиться в jQuery UI 1.10.3, але не 1.10.2
Bob Stein

2
Схоже, проблема також існує в jQuery UI 1.10.4 . Поки що я просто дотримуюся 1.10.2 !
Лхан

45

Це рішення працює, не коригуючи позиціонування нічого, ви просто клонуєте елемент і робите його абсолютно позиціонованим.

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

Помічник може бути функцією, якій потрібно повернути елемент DOM для перетягування.


+1 Дуже дякую, це працює для мене з сортуванням (я збирався спробувати щось подібне, але менш елегантне). У вас невеличка помилка з $ j! :)
Іен Коллінз

4
Для мене: перетягування взагалі не працює з цим і повертає помилки: TypeError: this.offsetParent [0] не визначено
ProblemsOfSumit

Я думаю, це ui.helper не тільки 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). Браузери, у яких немає помилки, тепер матимуть її, але перевернутий :)
manu

Примітка: деякі JS-аналізатори можуть скаржитися на "відсутній радіус" під час використання цього рішення. Щоб виправити, замініть var st = parseInt ($ (this) .data ("StartScrollTop")); з var st = parseInt ($ (this) .data ("startScrollTop"), 10); (тобто навести систему числення, яка буде використовуватися). 10 - за замовчуванням, але деякі аналізатори можуть вимагати, щоб це все-таки було присутнім (наприклад,
веб-пакет

7

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

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


Те саме для мене тут. Будь- position: relative;який батько з батьків спричиняє це.
wojtiku

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

1
Омг, це було, дякую, garrr, чому люди сьогодні не використовують Драгулу - спасибі!
Домінік

Дуже дякую! Батько батька, який займає посаду: родич спричинив це для мене
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, які всі працюють нормально.

Я виявив, що встановлення абсолютного чи фіксованого, з або без! Важливо, не допомогло, тому врешті-решт я додав рядок до своєї функції обробника перетягування:

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

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


1
Це працює, але коли ви прокручуєте під час перетягування, воно все одно змінює положення y. Рішення № 5 DarthJDG працює також під час прокрутки під час перетягування.
mirelon

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 tracker, щоб побачити, що вони про це думають .. було б круто, якби цю 4-річну помилку можна було остаточно виправити: /)


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

Здається, це робить обхідний шлях без необхідності використовувати позицію: 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

Я мав ту саму проблему і виявив, що все це через клас <body>навігатора bootstrap "navbar-fixed-top" із позицією до фіксованої, яка рухається вниз моїми 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);

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

// 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. Всі інші браузери працювали нормально. Видалення курсору At: {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.