jQuery draggable在页面滚动后在错误的位置显示帮助器

时间:2011-04-26 14:31:39

标签: jquery jquery-ui draggable jquery-ui-draggable

我正在使用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,
});

知道我能做些什么来解决这个问题吗?

21 个答案:

答案 0 :(得分:103)

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

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

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

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

答案 1 :(得分:43)

此解决方案无需调整任何内容的定位即可工作,您只需克隆元素并使其绝对定位。

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

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

答案 2 :(得分:11)

这对我有用:

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

答案 3 :(得分:7)

很抱歉写了另一个答案。 因为上面的答案中没有一个解决方案可以被我使用,所以我做了很多谷歌搜索,并在找到另一个合理的解决方案之前进行了许多令人沮丧的小编辑。

只要任何的父元素position设置为'relative',就会出现此问题。我不得不重新调整我的标记并改变我的CSS,但是通过从所有父母中移除此属性,我能够在所有浏览器中使.sortable()正常工作。

答案 4 :(得分:7)

看起来这个bug很常见,并且每次都有不同的解决方案。以上都不是我在互联网上找到的任何其他内容。 我正在使用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,我还没有在其他浏览器中测试过它。

答案 5 :(得分: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的问题(下面的评论)。

答案 6 :(得分:5)

我删除了溢出:

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

它完美无缺!

答案 7 :(得分:4)

看起来非常值得注意的是,这个bug应该已经解决了这么长时间。对我来说这是Safari和Chrome(即webkit浏览器)上的一个问题,但不是IE7 / 8/9上的问题,也不是Firefox上的问题。

我发现设置绝对或固定,有或没有!重要,没有帮助,所以最后我在我的拖动处理函数中添加了一行:

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

我原本希望能够将这一行与webkit特定相关,但奇怪的是它无处不在。 (期待我的评论很快说'不,实际上它搞砸了所有其他浏览器'。)

答案 8 :(得分: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);
         }
        });

答案 9 :(得分:1)

我在Firefox 21.0上使用JQuery draggable,我遇到了同样的问题。光标位于辅助图像上方一英寸处。我认为这是Jquery本身的一个问题,但仍未解决。我找到了解决此问题的方法,即使用draggable的“cursorAt”属性。我用它如下,但可以根据需要改变它。

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

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

答案 10 :(得分: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是具有overflow:auto;

的父级或祖先

计算出滚动元素的位置,并在每次移动/拖动时添加到帮助器的位置。

希望帮助某人,因为我浪费了大量时间。

答案 11 :(得分: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岁的bug会很酷:/)

答案 12 :(得分:1)

这似乎可以解决这个问题而无需在父级中使用position:absolute:)

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

答案 13 :(得分:1)

我设法通过添加display: inline-block解决了同样的问题 被拖动的物品

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

使用过的jQuery版本:

  • jQuery - 1.7.2
  • jQuery UI - 1.11.4

答案 14 :(得分:1)

我遇到了同样的问题,发现所有这一切都是因为一个带有固定位置的bootstrap导航栏“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);

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

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

当然,您必须尝试根据自己的网站确定正确的yOffset。

非常感谢DarthJDG指出了正确的方向。干杯!

答案 15 :(得分:0)

我退出使用jQueryUi draggable并转而使用名为jquery.even.drag的更好的插件,更小的代码大小,没有jQueryUI所有的废话。

我在容器中使用此插件制作了一个演示页面,其位置为:fixed

<强> Demo

希望这有助于某人,因为这个问题很严重。

答案 16 :(得分:0)

我有类似的问题,只有特定的IE 10在Windows 8上运行。所有其他浏览器都运行良好。删除cursorAt:{top:0}解决了问题。

答案 17 :(得分: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();
    }
});

答案 18 :(得分:0)

为什么不取光标位置?我正在使用可排序的插件,并使用此代码修复它:

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

答案 19 :(得分:0)

使用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'

答案 20 :(得分:0)

我在顶部使用粘性导航,并认为这是导致其他所有人似乎都遇到滚动问题的原因。我用cursorAt尝试了其他所有人的想法,尝试了遏制,但在CSS中取消html溢出之前,没有任何效果!有点疯狂的CSS会使一切搞砸了。这是我所做的,并且就像一种魅力:

html {
  overflow-x: unset;
}

body {
  overflow-x: hidden;
}