jQuery拖动功能在页面滚动后显示的助手位置错误。

80

我正在开发一个工作计划系统,使用jQuery draggabledroppable插件实现。用户可以将工作任务拖到不同的日期或用户上,然后通过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 这都是动态的,而且非常安全,所以我得写一个全新的例子;如果没有人能尽快回答的话,我会去做的。 - Alex
你能发布一下你的可拖拽元素拥有或继承的所有CSS属性吗? - DarthJDG
2
根据我之前的回答,这个问题似乎已经最终修复 - Patrick
21个回答

109

这可能与一个相关的错误报告有关,已经存在了相当长时间:http://bugs.jqueryui.com/ticket/3740

在我测试的每个浏览器上都似乎会发生这种情况(Chrome、FF4、IE9)。有几种方法可以解决这个问题:

1. 在您的CSS中使用 position:absolute;。绝对定位的元素似乎不受影响。

2. 确保父元素(即使是body)设置了 overflow:auto;。我的测试表明,这个解决方案可以修复位置,但它禁用了自动滚动功能。您仍然可以使用鼠标滚轮或箭头键进行滚动。

3. 手动应用以上错误报告中建议的修复措施,并彻底测试是否会导致其他问题。

4. 等待官方修复。虽然它已经多次推迟,但预计将在jQuery UI 1.9中解决。

5. 如果您确信它会在所有浏览器上发生,您可以将这些 hack 放入受影响的可拖动事件中以更正计算。不过需要测试很多不同的浏览器,所以只能作为最后的手段。

$('.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
好的,谢谢!(设置 overflow:auto 立即解决了问题。我将样式应用于单个表格单元格。) - Alex
2
在Firefox上,html元素上的overflow-y: scroll也会导致这个问题(Chrome可以正常工作),只需向下滚动并尝试拖动即可。 - digitalPBK
8
"helper: 'clone'"又回来了。这是一个级别为blocker的问题,比major高一级。tj.vantoll说:“1.10.3版本中引入的6个可拖动修复可能存在问题。”最简单的例子在这里:http://jsfiddle.net/7AxXE/。 - Bob Stein
7
确认,这个 bug 存在于 jQuery UI 1.10.3 版本中,但不存在于1.10.2版本。 - Bob Stein
2
看起来这个问题也存在于 jQuery UI 1.10.4 中。我现在只会使用 1.10.2 - lhan
显示剩余17条评论

46

这个解决方案不需要调整任何位置,只需克隆该元素并将其绝对定位即可。

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

这个帮助器可以是一个需要返回要拖动的DOM元素的函数。


4
对于我来说,拖动在这里完全不起作用并返回错误:TypeError: this.offsetParent[0]未定义。 - ProblemsOfSumit
1
谢谢你帮我解决了Sortable的问题。 - Bruno
在将此作为较少hacky解决方案之一进行投票后,我意识到对我来说问题在于父元素具有position: relative,正如@Josh Bambrick所发现的那样。 - Dominic
当使用position: relative;是绝对必要时,这是完美的修复方法。+1 - Barry Chapman
1
这是唯一对我有效的答案,而且它是最简单实现的。非常好的解决方案。 - Brett Gregson
显示剩余3条评论

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" - Roman Kiselenko
那是一个有趣的解决方案,但它只能在存在该漏洞的浏览器(Chrome)上工作。没有该漏洞的浏览器现在将拥有它,但是相反 :) - manu
注意:使用此解决方案时,某些JS解析器可能会抱怨“缺少基数”。要修复此问题,请将var st = parseInt($(this).data(“startingScrollTop”));替换为var st = parseInt($(this).data(“startingScrollTop”),10); (即提供要使用的数字系统)。 10是默认值,但某些解析器可能仍需要存在(例如webpack)。 - ripper17

8

抱歉又写了一个回答。 由于以上回答中的解决方案都不能被我使用,所以我做了很多谷歌搜索并进行了许多令人沮丧的微小编辑,最终找到了另一个合理的解决方案。

似乎只要父元素中的任何一个拥有position属性设置为“relative”,就会出现此问题。我不得不重新排列我的标记并修改我的CSS,但是通过从所有父代中删除此属性,我能够使.sortable()在所有浏览器中正常工作。


我这里也是一样的。任何父元素中的position: relative;都会导致这种情况发生。 - wojtiku
完全同意!对我来说,只是在body中的内联样式position:relative;需要被移除。在可拖动元素和body之间的父级元素似乎并不会引起问题。 - con
1
哦,原来如此,谢谢。为什么现在的人们不使用Dragula呢?感谢! - Dominic
非常感谢!祖先元素具有position:relative属性,导致了这个问题。 - wjk2a1
回应一下,这解决了我的问题!我正在使用js-parsons库,该库已经多年没有更新,因此仍在使用jQuery 1.7.2。从其中一个父元素中删除position: relative修复了该问题。 - tsumnia

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
我删除了溢出部分:
html {overflow-y: scroll; background: #fff;}

它完美地运行了!


5
这个bug已经被转移到http://bugs.jqueryui.com/ticket/6817,截至大约5天前(2013年12月16日左右),该问题似乎已经得到解决。目前的建议是使用来自http://code.jquery.com/ui/jquery-ui-git.js的最新开发版本或等待1.10.4版本(应该包含此修复程序)。 编辑: 看起来这个修复程序现在可能已经成为http://bugs.jqueryui.com/ticket/9315的一部分,但计划要等到1.11版本才发布。对于我和@Scott Alexander(下面的评论)来说,使用上面链接的jQuery源代码版本确实可以解决这个问题。

我正在使用1.10.4版本,但是那个错误仍然存在。不过,我使用了那个链接,现在一切都正常工作。 - Scott Alexander
@ScottAlexander 我所修复的问题可能与我之前想象的不同,已被添加到了其他工单。因此,我根据这一情况修改了我的答案。谢谢! - Patrick

4

这个 bug 竟然存在了这么长时间,令人惊讶。对我来说,在 Safari 和 Chrome(即 Webkit 浏览器)上有问题,但在 IE7/8/9 和 Firefox 上都能正常工作。

我发现设置 absolute 或 fixed,带或不带 !important 都没有帮助,最后我在拖动处理函数中添加了一行代码:

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

我本以为需要把那行代码写成适用于Webkit内核的,但奇怪的是,在所有浏览器上都可以正常工作。(我很快会发表评论说“不,实际上它破坏了所有其他浏览器”。)


1
这个可以用,但是当你拖动时滚动页面,它仍然会改变y轴位置。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
我正在Firefox 21.0上使用JQuery可拖动,并遇到相同的问题。光标停留在助手图像上方一英寸处。我认为这是Jquery本身的问题,仍未得到解决。我找到了一个解决此问题的方法,即使用可拖动的“cursorAt”属性。我按以下方式使用它,但可以根据需要进行更改。
$('.dragme').draggable({
helper: 'clone',    
cursor: 'move',    
cursorAt: {left: 50, top: 80}
});

注意:这适用于所有浏览器,所以在使用此代码后,请在所有浏览器中检查您的页面以获取正确的左侧和顶部位置。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接