从JQuery-UI包含中排除元素

时间:2018-07-17 17:14:54

标签: javascript jquery jquery-ui jquery-ui-draggable jquery-ui-resizable

我正在尝试允许一个元素在另一个元素内可拖动/调整大小,但不能在该元素的另一个子元素区域内拖动/调整大小。

给出以下表格行: table row with blue area spanning three columns and the fifth column greyed out

我希望能够在表格行中的任何位置拖动蓝色区域并调整其大小,但不能在灰色表格单元格的位置进行拖动(即它会在前四个单元格中自由移动/调整大小,但是在到达最后一个单元格时会停止移动)一个)。

我可以使用containment: '.middle tr'和{{1}中的containment: $el.closest('tr'),$el(其中JQuery.draggable是蓝色元素的选择器)选项将其约束到表行}},但我一直无法找到一种方法来排除收容中的最后一列。

如何从遏制区域中排除元素?

示例代码:

JQuery.resizable
$(function() {
  $("td").droppable({
    drop: function(event, ui) {
      var draggable = ui.draggable;

      var newLeft = draggable.offset().left - draggable.closest(".middle table").offset().left;
      var childNum = Math.round((newLeft + 100) / 100);

      var newContainer = $(this).closest('tr').find('td:nth-of-type(' + childNum + ')');

      draggable.css({
        top: '',
        left: ''
      });

      newContainer.append(draggable);
    },
  });
  $(".planning-spot").resizable({
    grid: [100, 10000000],
    handles: "e",
    containment: ".middle tr"
  }).each(function() {
    var $el = $(this);
    $el.draggable({
      containment: $el.closest('tr'),
      axis: 'x',
    });
  });
});
* {
  box-sizing: border-box;
  margin: 0;
  padding: 0;
}

table {
  border-collapse: collapse;
  overflow: hidden;
  table-layout: fixed;
  width: 500px;
  margin: 20px;
}

tr {
  position: relative;
  background: #FFF;
}

td, th {
  position: relative;
  padding: 0;
  width: 100px;
  height: 30px;
  border: 1px solid #000;
}

.planning-spot {
  position: absolute;
  top: 0;
  left: 0;
  height: 20px;
  width: 90px;
  border-radius: 10px;
  margin: 5px;
  text-align: center;
  z-index: 1;
  cursor: pointer;
  color: #FFF;
  width: 290px;
  background: #3CF;
}

.no-planning {
  background: #CCC;
}

http://jsfiddle.net/xpvt214o/668937/

我知道我可以分别在<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script> <script src="https://code.jquery.com/ui/1.12.1/jquery-ui.min.js"></script> <link href="https://code.jquery.com/ui/1.12.1/jquery-ui.min.css" rel="stylesheet"/> <div class="wrapper"> <div class="middle"> <table> <tbody> <tr> <td> <div></div> <div class="planning-spot">18 / 20</div> </td> <td> <div></div> </td> <td> <div></div> </td> <td> <div></div> </td> <td class="no-planning"> <div></div> </td> </tr> </tbody> </table> </div> </div>drop的{​​{1}}和stop函数期间检查位置,并在需要时撤消该操作(这是我的当前的解决方案),但是我正在寻找一种解决方案,以防止它首先被移到“不需要的”区域中。

2 个答案:

答案 0 :(得分:1)

您可以使用getBoundingClientRect()确定可拖动区域,并为每个可调整大小元素的宽度分配包含权给数组

$(function() {

  $("td").droppable({
    drop: function(event, ui) {
      var draggable = ui.draggable;

      var newLeft = draggable.offset().left - draggable.closest(".middle table").offset().left;
      var childNum = Math.round((newLeft + 100) / 100);

      var newContainer = $(this).closest('tr').find('td:nth-of-type(' + childNum + ')');

      draggable.css({
        top: '',
        left: ''
      });

      newContainer.append(draggable);
    },
  });
  $(".planning-spot").resizable({
    grid: [100, 10000000],
    handles: "e",
    containment: ".middle tr"
  }).each(function() {
    var $el = $(this);
    var bBoxTr = $el.closest('tr')[0].getBoundingClientRect();
    var bBoxTd = $el.closest('tr').children(".no-planning")[0].getBoundingClientRect();
    var x1 = bBoxTr.x, y1 = bBoxTr.y;
    var x2 = bBoxTr.right-bBoxTd.width, y2 = bBoxTr.bottom;
    $el.draggable({
//      containment: $el.closest('tr'),
      containment: [x1,y1,x2-$el.width()-10,y2],
      axis: 'x',
    });
  });
});
* {
  box-sizing: border-box;
  margin: 0;
  padding: 0;
}

table {
  border-collapse: no-collapse;
  overflow: hidden;
  table-layout: fixed;
  width: 500px;
  margin: 20px;
}

tr {
  position: relative;
  background: #FFF;
}

td, th {
  position: relative;
  padding: 0;
  width: 100px;
  height: 30px;
  border: 1px solid #000;
}

.planning-spot {
  position: absolute;
  top: 0;
  left: 0;
  height: 20px;
  width: 90px;
  border-radius: 10px;
  margin: 5px;
  text-align: center;
  z-index: 1;
  cursor: pointer;
  color: #FFF;
  width: 290px;
  background: #3CF;
}

.no-planning {
  background: #CCC;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://code.jquery.com/ui/1.12.1/jquery-ui.min.js"></script>
<link href="https://code.jquery.com/ui/1.12.1/jquery-ui.min.css" rel="stylesheet"/>
<div class="wrapper">
    <div class="middle">
      <table>
        <tbody>
          <tr id="test">
            <td>
              <div></div>
              <div class="planning-spot">18 / 20</div>
            </td>
            <td>
              <div></div>
            </td>
            <td>
              <div></div>
            </td>
            <td>
              <div></div>
            </td>
            <td class="no-planning">
              <div></div>
            </td>
          </tr>
        </tbody>
      </table>
    </div>
</div>

编辑:

由于并非所有浏览器都支持getBoundingClientRect();,因此最好使用jquery功能position()height()width();

请参见下面的修订代码段,函数getDragArea返回一个数组,其中包含拖动区域的坐标。我添加了一个侦听器(鼠标悬停),可以在需要时重置拖动区域。 该表包装在滚动div中以测试行为。

$(function() {

  $("td").droppable({
    drop: function(event, ui) {
      var draggable = ui.draggable;

      var newLeft = draggable.offset().left - draggable.closest(".middle table").offset().left;
      var childNum = Math.round((newLeft + 100) / 100);

      var newContainer = $(this).closest('tr').find('td:nth-of-type(' + childNum + ')');

      draggable.css({
        top: '',
        left: ''
      });

      newContainer.append(draggable);
    },
  });
  $(".planning-spot").resizable({
    grid: [100, 10000000],
    handles: "e",
    containment: ".middle tr"
  }).each(function() {
    $(this).on('mouseover',function(){
      $(this).draggable({
      containment: getDragArea($(this)),
      axis: 'x',
    });
	})
  });
  
 function getDragArea($el){
    var $tr = $el.closest('tr');
  	var $tds = $el.closest('tr').children(".no-planning");
	  var width = $el.closest('tr').width()-$tds.width()*$tds.length;
	  var height = $el.closest('tr').height();
    var position = $el.closest('tr').position();
    var x1 = position.left, y1 = position.top;
    var x2 = x1+width, y2 = y1+height;
    return [x1,y1,x2-$el.width()-10,y2]
   }
});
* {
  box-sizing: border-box;
  margin: 0;
  padding: 0;
}

table {
  border-collapse: no-collapse;
  overflow: hidden;
  table-layout: fixed;
  width: 500px;
  margin: 20px;
}

tr {
  position: relative;
  background: #FFF;
}

td, th {
  position: relative;
  padding: 0;
  width: 100px;
  height: 30px;
  border: 1px solid #000;
}

.planning-spot {
  position: absolute;
  top: 0;
  left: 0;
  height: 20px;
  width: 90px;
  border-radius: 10px;
  margin: 5px;
  text-align: center;
  z-index: 1;
  cursor: pointer;
  color: #FFF;
  width: 290px;
  background: #3CF;
}

.no-planning {
  background: #CCC;
}

.wrapper{
  overflow:auto;
  width:500px;
  height:120px;
  border: solid 1px red;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://code.jquery.com/ui/1.12.1/jquery-ui.min.js"></script>
<link href="https://code.jquery.com/ui/1.12.1/jquery-ui.min.css" rel="stylesheet"/>
<div class="wrapper">
    <div class="middle">
      <table>
        <tbody>
          <tr id="test">
            <td>
              <div></div>
              <div class="planning-spot">18 / 20</div>
            </td>
            <td>
              <div></div>
            </td>
            <td>
              <div></div>
            </td>
            <td>
              <div></div>
            </td>
            <td class="no-planning">
              <div></div>
            </td>
            <td class="no-planning">
              <div></div>
            </td>
          </tr>
        </tbody>
      </table>
      <br>
      <br>
      <br>
      <br>
      <br>
      <br>
      <br>
      <br>
    </div>
</div>

答案 1 :(得分:0)

我通过检查拖动事件是否会导致与不可拖动的物品发生碰撞来解决问题。

以下结帐代码:

$(function() {
	var nonDragableItems = $(".no-planning");
  $("td").droppable({
    drop: function(event, ui) {
      var draggable = ui.draggable;

      var newLeft = draggable.offset().left - draggable.closest(".middle table").offset().left;
      var childNum = Math.round((newLeft + 100) / 100);

      var newContainer = $(this).closest('tr').find('td:nth-of-type(' + childNum + ')');

      draggable.css({
        top: '',
        left: ''
      });

      newContainer.append(draggable);
    },
  });
  
  function onDrag(e, ui){
    var dragElemRect = ui.helper[0].getBoundingClientRect();
    for(var i=0;i<nonDragableItems.length;i++){
      var elemRect = nonDragableItems[i].getBoundingClientRect();
      if(areColliding(dragElemRect, elemRect))
        return false;
    }
  }

  function areColliding(rect1, rect2){
    if(rect1.bottom <= rect2.top ||
       rect1.top >= rect2.bottom ||
       rect1.left >= rect2.right ||
       rect1.right <= rect2.left)
          return false;
        return true;
  }
  
  $(".planning-spot").resizable({
    grid: [100, 10000000],
    handles: "e",
    containment: ".middle tr"
  }).each(function() {
    var $el = $(this);
    $el.draggable({
      containment: $el.closest('tr'),
      axis: 'x',
      drag: onDrag
    });
  });
});
* {
  box-sizing: border-box;
  margin: 0;
  padding: 0;
}

table {
  border-collapse: collapse;
  overflow: hidden;
  table-layout: fixed;
  width: 500px;
  margin: 20px;
}

tr {
  position: relative;
  background: #FFF;
}

td, th {
  position: relative;
  padding: 0;
  width: 100px;
  height: 30px;
  border: 1px solid #000;
}

.planning-spot {
  position: absolute;
  top: 0;
  left: 0;
  height: 20px;
  width: 90px;
  border-radius: 10px;
  margin: 5px;
  text-align: center;
  z-index: 1;
  cursor: pointer;
  color: #FFF;
  width: 290px;
  background: #3CF;
}

.no-planning {
  background: #CCC;
}
<link href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css" rel="stylesheet"/>
<link href="https://cdnjs.cloudflare.com/ajax/libs/jqueryui/1.12.1/jquery-ui.min.css" rel="stylesheet"/>

<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jqueryui/1.12.1/jquery-ui.min.js"></script>

<div class="wrapper">
    <div class="middle">
      <table>
        <tbody>
          <tr>
            <td>
              <div></div>
              <div class="planning-spot">18 / 20</div>
            </td>
            <td>
              <div></div>
            </td>
            <td>
              <div></div>
            </td>
            <td>
              <div></div>
            </td>
            <td class="no-planning">
              <div></div>
            </td>
          </tr>
        </tbody>
      </table>
    </div>
</div>