首页
学习
活动
专区
工具
TVP
发布
社区首页 >问答首页 >如何修复连接的可排序的错误定位的可拖动帮助器(部分由浮动/相对定位的父元素引起)?

如何修复连接的可排序的错误定位的可拖动帮助器(部分由浮动/相对定位的父元素引起)?
EN

Stack Overflow用户
提问于 2015-11-13 08:22:55
回答 3查看 4.8K关注 0票数 19

前言

我遇到了一个问题,当使用放置在浮动的、相对定位的父元素中的draggables + sortables时,可拖动的辅助对象被错误地偏移。浮动的父元素是Bootstrap列,其中多个可排序列表放在一个列中,而可拖放的列表放在另一个列中。

示例

下面是一个有效的示例代码片段

代码语言:javascript
复制
$('.sortable').sortable({
  connectWith: '.sortable',
  revert: 600,
  forcePlaceholderSize: true,
  placeholder: 'ui-sortable-placeholder',
  tolerance: 'pointer'
}).disableSelection();

$('.draggable').draggable({
  connectToSortable: '.sortable',
  helper: 'clone',
  revert: true
}).disableSelection();
代码语言:javascript
复制
.sortable-container {
  display: inline-block;
  width: 100px;
  vertical-align: top;
}
.sortable {
  cursor: move;
  margin: 0;
  padding: 0;
  list-style-type: none;
  vertical-align: top;
  border: 1px solid #000;
}
.ui-sortable-placeholder {
  background: #ff0000;
}
#draggables {
  margin: 0;
  padding: 0;
  list-style-type: none;
}
.draggable {
  margin: 4px;
  cursor: move;
  color: #fff;
  background: #5dd1ff;
}
代码语言:javascript
复制
<link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.5/css/bootstrap.min.css" rel="stylesheet" />
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://code.jquery.com/ui/1.11.3/jquery-ui.min.js"></script>

<div class='container-fluid'>
  <div class="row">
    <div class="col-xs-3">
      <p>foo</p>
      <p>bar</p>
    </div>
    <div class="col-xs-3">
      <p>foo</p>
      <p>bar</p>
    </div>
    <div class="col-xs-6">
      <p>foo</p>
      <p>bar</p>
    </div>
  </div>
  <div class='row'>
    <div class='col-xs-6'>
      <div id='sortables'>
        <div class='sortable-container'>
          <ul class='sortable'>
            <li>sortable 1</li>
            <li>sortable 2</li>
            <li>sortable 3</li>
            <li>sortable 4</li>
            <li>sortable 5</li>
            <li>sortable 6</li>
          </ul>
        </div>
        <div class='sortable-container'>
          <ul class='sortable'>
            <li>sortable 1</li>
            <li>sortable 2</li>
            <li>sortable 3</li>
            <li>sortable 4</li>
            <li>sortable 5</li>
            <li>sortable 6</li>
          </ul>
        </div>
        <div class='sortable-container'>
          <ul class='sortable'>
            <li>sortable 1</li>
            <li>sortable 2</li>
            <li>sortable 3</li>
            <li>sortable 4</li>
            <li>sortable 5</li>
            <li>sortable 6</li>
          </ul>
        </div>
      </div>
    </div>

    <div class='col-xs-6'>
      <ul id='draggables'>
        <li class='draggable'>draggable 1</li>
        <li class='draggable'>draggable 2</li>
        <li class='draggable'>draggable 3</li>
      </ul>
    </div>
  </div>
</div>

更新2015年11月16日我修改了代码示例,以更好地反映我的实际使用上下文,其中包含draggables/sortables的行上方还有更多行。

一个screencast和一个显示发生了什么的静止图像

进一步解释

当将右侧列中的一个可拖动对象拖到左侧的一个可排序列表上时,如果没有将其拖放,而是将其拖出可排序列表的边界框,则辅助对象的位置不正确,它向左移动了几百个像素,就好像它错误地包含了某种偏移量(看起来可能是原始的可拖动位置)。

有趣的是,当可拖放对象与可排序对象放置在同一父元素中时,这不会发生,至少它不会水平移动,而是当可拖放对象快速向上/向下或向左/向右移入/移出可排序列表时。

水平移动以某种方式与浮动/相对定位的父元素相关,禁用浮动或相对定位可以修复它。但是,我想保持原样,并找到另一个修复/解决方法。当不涉及浮动/相对定位时,垂直移位也会发生,所以我猜这个问题会更多一些。

更新2015年11月15日 - jQuery UI更改

看起来jQuery UI 1.11.4改变了一些行为,现在它不会在你离开可排序的边界框时立即水平移动,但你必须首先在两个或多个可排序之间移动。除此之外,be行为似乎没有变化。

更新2015年11月16日 - Update option

最初,我尝试使用appendTo作为变通方法,因为帮助器将保留在列表之外,虽然这对我的原始示例代码是正确的,但它不适用于更新的示例代码,在更新的示例代码中,更多的行被放置在保存可拖动对象/可排序对象的行之上,它们导致帮助器垂直移动。

问题

有没有人知道有问题的水平偏移量到底来自哪里,以及如何在继续使用浮动/相对定位的父元素的同时修复它?

看到中也发生了垂直偏移,我认为这是一个与父元素的样式无关的错误。

更新2015年11月15日 -已找到垂直偏移问题

垂直偏移似乎与应用于可拖动对象的边距有关,没有这一点,它似乎工作得很好。

我已经报告了这两个错误,但我仍然在寻找一个修复/解决方法,我可以应用自己,直到这个问题可能在库中修复,也可能不会。

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2015-11-17 04:13:12

奇怪的是,它似乎与jquery-UI10.4一起工作得更好。不同之处在于,在10.4中,可拖动帮助器保留在其原始div中,并被克隆到可排序中,但被隐藏。因此,计算更容易进行。

在11.4中,辅助对象被附加到它被拖动到的可排序表中,这使得精确的偏移量计算很难理解。您必须不断地更改父偏移量,并跟踪它是哪个可排序的、它是哪个可排序的、可排序的位置等等。很明显,这里面有个bug。

一个简单的解决方案是从10.4获取connectToSortable插件。你将不得不检查不想要的副作用,但很快它似乎就起作用了。您可以使用不同的名称,以便保留原始名称。如下所示:

代码语言:javascript
复制
$.ui.plugin.add("draggable", "connectToSortable104", {
    // You take the whole connectToSortable plugin from  
    // here: https://code.jquery.com/ui/1.10.4/jquery-ui.js  
    // In 11.4 you'll need to add draggable parameter 
    // for example: to the event methods,
    // start: function(event, ui, draggable)
    ...

请参阅http://jsfiddle.net/gsnojkbc/2/

编辑:

我不认为额外的div是导致问题的原因,实际上是jQuery11.4中connectToSortable工作方式的错误导致了问题。要允许在排序中移动辅助对象,并且仍然跟踪适当的偏移量,您需要在每次辅助对象更改div时重新调整一些数据。它的实现方式有两个缺陷:

第一个是在draggable中有一个与其他事件通用的refreshOffsets方法。例如,当您单击可拖动对象时,就会使用它。因此它会尝试根据点击来计算偏移量。但是当从可排序事件调用refreshOffsets时,它会弄乱点击偏移量。这个问题可以通过修改refreshOffsets方法来解决,这样就不需要考虑event.pageX和Y。如下所示:

代码语言:javascript
复制
$.ui.draggable.prototype._refreshOffsetsSortable = function(event, draggable){

        this.offset = {
                top: this.positionAbs.top - this.margins.top,
                left: this.positionAbs.left - this.margins.left,
                scroll: false,
                parent: this._getParentOffset(),
                relative: this._getRelativeOffset()
            };

            this.offset.click = draggable.offset.click;
    }

另一个问题发生是因为您有许多可排序。基本上,需要完成的另一个操作是更改父偏移量。现在的方法是保存之前的父对象。通常情况下,它可以工作,但如果移动太快,序列会使它成为保存的父对象是可排序的,而不是原始的父对象。您可以通过在拖动开始时保存父对象来修复此问题,这样做在任何情况下都更有意义。如下所示:

代码语言:javascript
复制
$.ui.plugin.add( "draggable", "connectToSortableFixed", {
    start: function( event, ui, draggable ) {
        var uiSortable = $.extend( {}, ui, {
            item: draggable.element
        });
        draggable._parent = this.parent();
...

查看此处:http://jsfiddle.net/24a8q49j/1/

票数 6
EN

Stack Overflow用户

发布于 2015-11-21 22:42:38

一种仅限JavaScript的简单解决方法是在开始拖动时将偏移存储到鼠标,然后强制ui.helper始终具有与鼠标相同的偏移:

代码语言:javascript
复制
[...]
var offset_start = {};

$('.draggable').draggable({
  connectToSortable: '.sortable',
  helper: 'clone',
  revert: true,
  start: function(e, ui) {
      offset_start = {
          x: ui.position.left - e.pageX,
          y: ui.position.top - e.pageY
      }
  },
  drag: function(e, ui) {
      ui.position.top = e.pageY + offset_start.y
      ui.position.left = e.pageX + offset_start.x
  }
}).disableSelection();

请参阅updated jsfiddle

对于简单的情况,这是一个简单的变通方法,但如果您引入边界(帮助器不能离开的地方)等,则需要做更多的工作。

编辑:对于您的代码片段,我想出了另一个解决方案(因为另一个并不像预期的那样工作--获得初始偏移量比我想象的要难……):在将辅助对象附加到正文之后,只需强制项目停留在鼠标指针处,而不考虑初始偏移量。它不是100%好,因为当开始拖动时,它可能会“跳”到鼠标--但它至少会停留在那里……

代码语言:javascript
复制
$('.draggable').draggable({
  connectToSortable: '.sortable',
  helper: 'clone',
  revert: 'invalid',
  appendTo: 'body',
  drag: function(e, ui) {
    if (!ui.helper.parent().is('body')) {
      ui.helper.appendTo($('body'));
    }
    ui.position.top = e.pageY - 10;
    ui.position.left = e.pageX - 25;
  }
}).disableSelection();

代码语言:javascript
复制
$('.sortable').sortable({
  connectWith: '.sortable',
  revert: 600,
  forcePlaceholderSize: true,
  placeholder: 'ui-sortable-placeholder',
  tolerance: 'pointer'
}).disableSelection();


$('.draggable').draggable({
  connectToSortable: '.sortable',
  helper: 'clone',
  revert: 'invalid',
  appendTo: 'body',
  scroll: false,
  drag: function(e, ui) {
    if (!ui.helper.parent().is('body')) {
      ui.helper.appendTo($('body'));
    }
    ui.position.top = e.pageY - 15;
    ui.position.left = e.pageX - 25;
  }
}).disableSelection()
代码语言:javascript
复制
.sortable-container {
  display: inline-block;
  width: 100px;
  vertical-align: top;
}
.sortable {
  cursor: move;
  margin: 0;
  padding: 0;
  list-style-type: none;
  vertical-align: top;
  border: 1px solid #000;
}
.ui-sortable-placeholder {
  background: #ff0000;
}
#draggables {
  margin: 0;
  padding: 0;
  list-style-type: none;
}
.draggable {
  margin: 4px;
  cursor: move;
  color: #fff;
  background: #5dd1ff;
}
代码语言:javascript
复制
<link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.5/css/bootstrap.min.css" rel="stylesheet" />
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://code.jquery.com/ui/1.11.3/jquery-ui.min.js"></script>

<div class='container-fluid'>
  <div class="row">
    <div class="col-xs-3">
      <p>foo</p>
      <p>bar</p>
    </div>
    <div class="col-xs-3">
      <p>foo</p>
      <p>bar</p>
    </div>
    <div class="col-xs-6">
      <p>foo</p>
      <p>bar</p>
    </div>
  </div>
  <div class='row'>
    <div class='col-xs-6'>
      <div id='sortables'>
        <div class='sortable-container'>
          <ul class='sortable'>
            <li>sortable 1</li>
            <li>sortable 2</li>
            <li>sortable 3</li>
            <li>sortable 4</li>
            <li>sortable 5</li>
            <li>sortable 6</li>
          </ul>
        </div>
        <div class='sortable-container'>
          <ul class='sortable'>
            <li>sortable 1</li>
            <li>sortable 2</li>
            <li>sortable 3</li>
            <li>sortable 4</li>
            <li>sortable 5</li>
            <li>sortable 6</li>
          </ul>
        </div>
        <div class='sortable-container'>
          <ul class='sortable'>
            <li>sortable 1</li>
            <li>sortable 2</li>
            <li>sortable 3</li>
            <li>sortable 4</li>
            <li>sortable 5</li>
            <li>sortable 6</li>
          </ul>
        </div>
      </div>
    </div>

    <div class='col-xs-6'>
      <ul id='draggables'>
        <li class='draggable'>draggable 1</li>
        <li class='draggable'>draggable 2</li>
        <li class='draggable'>draggable 3</li>
      </ul>
    </div>
  </div>
</div>

票数 4
EN

Stack Overflow用户

发布于 2015-11-16 21:35:32

请参阅https://jsfiddle.net/tsLcjw9c/1/

我在draggables列表上设置了一个固定的宽度(100px),以便可拖动的辅助对象具有与列表项相同的宽度,这可以防止初始的水平偏移。

在可排序容器上拖动时得到的大水平偏移确实似乎是jquery UI中的一个错误,但它似乎恰好是可排序容器宽度的100%,这就是我添加以下css的原因:

代码语言:javascript
复制
.sortable .ui-draggable-dragging:not(.ui-sortable-helper){
    margin-left:100%;
}

进入和离开可排序列表后得到的垂直偏移量似乎是由可拖动项的4px边距引起的,我删除了它。你可以使用透明边框和框大小来达到相同的效果:边框;或者添加填充并将背景剪辑设置为padding。

最后,你想要的600ms动画在我的浏览器(Chrome)中以一种奇怪的方式发生,它去了2个不同的位置,最后动画到了正确的位置。这就是我现在禁用动画的原因。您可以尝试覆盖可排序jQuery中的drop事件,以便手动设置指向正确位置的动画。

下面是jsfiddle代码:

html

代码语言:javascript
复制
<div class='container-fluid'>
  <div class='row'>
    <div class='col-xs-6'>
      <div id='sortables'>
        <div class='sortable-container'>
          <ul class='sortable'>
            <li>sortable 1</li>
            <li>sortable 2</li>
            <li>sortable 3</li>
            <li>sortable 4</li>
            <li>sortable 5</li>
            <li>sortable 6</li>
          </ul>
        </div>
        <div class='sortable-container'>
          <ul class='sortable'>
            <li>sortable 1</li>
            <li>sortable 2</li>
            <li>sortable 3</li>
            <li>sortable 4</li>
            <li>sortable 5</li>
            <li>sortable 6</li>
          </ul>
        </div>
        <div class='sortable-container'>
          <ul class='sortable'>
            <li>sortable 1</li>
            <li>sortable 2</li>
            <li>sortable 3</li>
            <li>sortable 4</li>
            <li>sortable 5</li>
            <li>sortable 6</li>
          </ul>
        </div>
      </div>
    </div>

    <div class='col-xs-6'>
      <ul id='draggables'>
        <li class='draggable'>draggable 1</li>
        <li class='draggable'>draggable 2</li>
        <li class='draggable'>draggable 3</li>
      </ul>
    </div>
  </div>
</div>

jquery

代码语言:javascript
复制
$('.sortable').sortable({
  connectWith: '.sortable',
  revert: 0,
  forcePlaceholderSize: true,
  placeholder: 'ui-sortable-placeholder',
  tolerance: 'pointer'
}).disableSelection();

$('.draggable').draggable({
  connectToSortable: '.sortable',
  helper: 'clone',
  revert: false
}).disableSelection();

css

代码语言:javascript
复制
.sortable-container {
  display: inline-block;
  width: 100px;
  vertical-align: top;
}
.sortable {
  cursor: move;
  margin: 0;
  padding: 0;
  list-style-type: none;
  vertical-align: top;
  border: 1px solid #000;
}
.ui-sortable-placeholder {
  background: #ff0000;
}
#draggables {
  margin: 0;
  padding: 0;
  list-style-type: none;
}
.draggable {
  cursor: move;
  color: #fff;
  background: #5dd1ff;
    width:100px;
    max-width:100%;
}
.sortable .ui-draggable-dragging:not(.ui-sortable-helper){
    margin-left:100%;
}
票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/33683926

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档