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 2011年

2
根据我在下面的回答,这个问题似乎终于得到解决
Patrick

Answers:


107

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

这似乎发生在我测试过的所有浏览器(Chrome,FF4,IE9)上。有几种方法可以解决此问题:

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

2.确保已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
太好了,谢谢!(设置溢出:立即将其自动修复。我将样式应用于单个表格单元格
Alex

2
jsfiddle.net/a2hzt/5 溢出-y:在html元素上滚动也会在Firefox(chrome作品)上产生此问题,只需向下滚动并尝试拖动即可。
digitalPBK 2012年

8
真是太棒了helper: "clone"bugs.jqueryui.com/ticket/9315 级别阻止程序,比主要级别高出一个档次。tj.vantoll说:“有6个可拖曳的修补程序落入1.10.3,可能会令人怀疑。” 最简单的示例:jsfiddle.net/7AxXE
Bob Stein

7
确认,此错误在jQuery UI 1.10.3中,但不在1.10.2中
Bob Stein

2
看起来问题还存在于jQuery UI 1.10.4中。我现在只会坚持使用1.10.2
lhan 2014年

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,而且是ui.helper
Mohammed Joraid 2014年

1
谢谢您协助我进行Sortable
BG BRUNO 2014年

1
这是唯一对我有用的答案,并且是最简单的实现。绝佳解决方案
Brett Gregson

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 2015年

注意:使用此解决方案时,某些JS解析器可能会抱怨“基数丢失”。要修复,请替换var st = parseInt($(this).data(“ startingScrollTop”)); 与var st = parseInt($(this).data(“ startingScrollTop”),10); (即提供要使用的数字系统)。默认值为10,但某些解析器可能仍然要求此设置存在(例如webpack)
ripper17 '18

7

很抱歉写另一个答案。由于上述答案中的任何一种解决方案都无法被我使用,因此在找到另一个合理的解决方案之前,我做了很多谷歌搜索并做了许多令人沮丧的小修改。

每当任何父元素position设置为“相对”时,似乎都会发生此问题。我不得不重新排列标记并更改CSS,但是通过从所有父级中删除此属性,我可以.sortable()在所有浏览器中正常工作。


我这里也一样。任何position: relative;在任何父导致这种情况发生。
wojtiku

完全同意!对我来说,这只是体内的内嵌样式与position: relative;其中已被删除..可拖动和车身之间的父元素似乎不..让problemes这里
CON

1
天哪,谢谢,加尔(Garrr)为什么现在这个时代人们不使用Dragula-谢谢!
多米尼克

非常感谢!拥有位置:亲戚的父母的父母为我带来了
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 2014年


5

该错误已移至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版之前发布。使用上面链接的jQuery源控制版本确实可以解决我和@Scott Alexander的问题(下面的评论)。


我正在使用1.10.4,但该错误仍然存​​在,尽管使用了该链接,但一切正常。
Scott Alexander

@ScottAlexander该修复程序可能已附加到与我想像不同的票证上。我已经基于此编辑了答案。谢谢!
Patrick

4

似乎值得注意的是,该错误应该已经修复了这么长时间。对我来说,这是在Safari和Chrome(即Webkit浏览器)上的问题,但在IE7 / 8/9或Firefox上都没有问题,它们都可以正常工作

我发现设置绝对值或固定值(带或不带!important)都无济于事,因此最后我在拖动处理函数中添加了一行:

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

我曾期望需要使该行特定于Webkit,但是奇怪的是,它在任何地方都可以正常工作。(期待我的评论很快说:“不,实际上它弄乱了所有其他浏览器”。)


1
这是可行的,但是在拖动时滚动时,它仍会移动y位置。DarthJDG的解决方案编号5在拖动时滚动时也适用。
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跟踪器,以查看他们对此的看法..如果最终可以更正这个已有4年历史的错误,那就太酷了:/)


1

我在Firefox 21.0上使用JQuery Draggable,但遇到了同样的问题。光标停留在辅助图像上方一英寸处。我认为这是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; 
     } 
});

谢谢!这是唯一对我有用的东西。(我不确定我是否理解问题。我的问题是,当拖动从顶部的滚动条开始时,拖动,拖动滚动工作正常。如果滚动条从下方开始,则出现偏移问题)
John Smith

1

我设法通过添加display: inline-block 到拖动的项目来解决相同的问题

添加position: relative对我不起作用(jQueryposition: absolute在拖动开始时将其覆盖)

使用的jQuery版本:

  • jQuery-1.7.2
  • jQuery UI-1.11.4

position: relative如果将其移至更高级别的容器元素,则可能有效。我知道它现在无济于事,但仅供参考,也许对将来遇到麻烦的开发人员也是如此。
gdibble

1

我遇到了同样的问题,发现所有这一切都是由于引导程序navbar“ navbar-fixed-top”类具有固定位置,<body>该类比我的顶部低60px <html>。因此,当我在网站中移动可拖动表单时,光标出现在表单顶部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);

现在,当我使用引导导航栏初始化站点中的可拖动元素/表单时:

// 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

我遇到了类似的问题,只是在Windows 8上运行了特定的IE10。所有其他浏览器都工作正常。删除cursorAt:{top:0}解决了该问题。


0

我在这里尝试了各种答案,包括更新jQuery,发现这对我有用。我在最新的chrome和IE上进行了测试。我猜这将是一个不同的解决方案的问题,具体取决于您的UI布局。

$('{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尝试了其他所有人的想法,尝试了遏制,但在CSS中取消html溢出之前,没有任何效果!有点疯狂的CSS会使一切搞砸了。这是我所做的,并且就像一个魅力一样工作:

html {
  overflow-x: unset;
}

body {
  overflow-x: hidden;
}
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.