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个回答

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的父元素或祖先元素;
每次移动/拖动时,计算出滚动元素的位置,并将其添加到助手的位置。
希望这能帮助某些人,因为我在这上面浪费了很多时间。

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
这似乎可以避免在父元素中使用position:absolute的解决方法 :)
$("body").draggable({
     drag: function(event, ui) { 
         return false; 
     } 
});

谢谢!这是唯一对我有效的方法。(我不确定我理解问题...我的问题是,当滚动条从顶部开始拖动时,拖动和滚动工作正常。如果滚动条从较低位置开始,则会出现偏移问题) - John Smith

1

我成功地使用添加display: inline-block到拖动的项目中解决了同样的问题。

对我来说,添加position: relative并没有起作用(jQuery在拖动开始时用position: absolute覆盖它)。

使用的jQuery版本:

  • jQuery - 1.7.2
  • jQuery UI - 1.11.4

如果您将position: relative移动到更高级别的容器元素中,它可能会起作用。我知道现在这并没有什么帮助,但这是供参考,也许对未来遇到问题的开发人员有所帮助。 - gdibble

1
我在顶部使用了一个固定导航,认为这是导致其他人遇到的滚动问题的原因。我尝试了其他人的光标位置和包含方法,但都没有起作用,除了在CSS中取消设置html溢出!一点点CSS就可以搞砸一切,真是疯狂。这是我所做的,它像魔法一样奏效:
html {
  overflow-x: unset;
}

body {
  overflow-x: hidden;
}

1
我遇到了同样的问题,发现原因是由于Bootstrap导航栏使用了"navbar-fixed-top"类,使得它的位置被固定在页面顶部,并使得我的标签的位置比标签的顶部低了60个像素。因此,当我在我的网站上移动可拖动表单时,光标会出现在表单的顶部之上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

为什么不获取光标位置?我正在使用可排序插件,并使用以下代码进行修复:

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

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'

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

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


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