【问题标题】:JQuery: z-index ordering with draggable divsJQuery:可拖动 div 的 z-index 排序
【发布时间】:2019-08-05 01:44:18
【问题描述】:

在下面的代码中我有:

  1. 点击相应按钮时弹出的 div
  2. 如果你拖动它们,(最后一个)活动对象应该在顶部

目前我的代码在最后一个活动元素被买到前面的地方不能按预期工作。我正在尝试创建一个可扩展的解决方案,以后可能会有大约五个左右的按钮具有不同的内容。

另外,有没有办法让 div 在显示它们的按钮附近弹出?如果我在点击之前拖动按钮,距离有点大。

我目前的尝试是这样的:

$(function() {
	/* Combine on ready logic into one place */
	$("#button-one").draggable({
		stack: 'div',
		containment: "body"
	});
	$("#content-one").draggable({
		stack: 'div',
		containment: "body"
	});
	/* Hide all trip elements except for first */
	$('.trip', '#content-one').not(':first').hide();
});
$('#button-one').on('mouseup', function() {
	if (!$(this).hasClass('ui-draggable-dragging')) {
		$("#content-one").toggle();
	}
});
$('#content-one').on('mouseup', function() {
	/* Reuse same logic in #button mouseup handler */
	if (!$(this).hasClass('ui-draggable-dragging')) {
		/* 
		If content element if not dragging, treat mouse up as conclusion
		of click event and rotate visibility of trip elements like this
		*/
		let trip = $('.trip:visible', '#content-one');
		let next = trip.next().length === 0 ? $('.trip:first', '#content-one') : trip.next();
		trip.hide();
		next.show();
	}
});
$(function() {
	$("#button-two").draggable({
		stack: 'div',
		containment: "body"
	});
});
$('#button-two').on('mouseup', function() {
	if (!$(this).hasClass('ui-draggable-dragging')) {
		// your click function
		$("#content-two").toggle();
	}
});
$(function() {
	$("#content-two").draggable({
		stack: 'div',
		containment: "body"
	});
});
body,
html {
position: absolute;
padding: 0;
margin: 0;
width: 100%;
overflow-x: hidden;
overflow-y: inherit;
cursor: default;
}

#content {
max-width: 100vw;
height: 150vh;
}

#one {
left: 5%;
top: 5%;
position: absolute;
}

#button-one {
width: 100px;
height: 100px;
background-color: cyan;
position: absolute;
}

#content-one {
display: none;
cursor: all-scroll;
top: 10%;
left: 10%;
position: absolute;
top: 20px;
left: 20px;
}

.trip {
width: 200px;
height: 200px;
background-color: blue;
color: white;
}

#two {
left: 15%;
top: 15%;
position: absolute;
}

#button-two {
width: 100px;
height: 100px;
background-color: darkgrey;
position: absolute;
}

#content-two {
display: none;
cursor: all-scroll;
position: absolute;
top: 20px;
left: 20px;
width: 200px;
height: 200px;
background-color: green;
color: white;
}
<div id="content">

<div id="one">
<div id="button-one">Button 1</div>

<div id="content-one">
<div class="trip">div 1</div>
<div class="trip">div 2</div>
<div class="trip">div 3</div>
</div>
</div>

<div id="two">
<div id="button-two">Button 2</div>
<div id="content-two">Hey</div>
</div>

</div>

<script src="https://code.jquery.com/jquery-1.7.2.min.js"></script>
<script src="https://code.jquery.com/ui/1.8.21/jquery-ui.min.js"></script>
<script src="https://raw.githubusercontent.com/furf/jquery-ui-touch-punch/master/jquery.ui.touch-punch.min.js"></script>

感谢您的帮助! :)

【问题讨论】:

  • 当内容打开并且开始拖动按钮时,内容会发生什么?
  • @RokoC.Buljan 在这种情况下,内容应该保持在当前位置,并且按钮应该在所有对象的顶部。只有当按钮被点击时,内容才会被隐藏。

标签: javascript jquery html css draggable


【解决方案1】:

基于this answer of mine to your previous question - 经过一些修改,我会这样做:

  • 使用data-*属性存储目标内容选择器ID
  • 使用Event.clientX / Y - 获取点击坐标
  • 使用.css({left: X, top: Y}) 放置您的内容
  • 将所有元素放在同一个父级中,以解决有问题的 z-indexing 并帮助 stack: '.draggable', 完成工作

jQuery($ => {

  const $drag = $('.draggable').draggable({
    stack: '.draggable',
    containment: 'body'
  });

  // Fix out-of-containment glitch
  $($drag.draggable('option').containment).on('mouseleave', () => $drag.trigger('mouseup')); 
  
  let z = 10; // Contents zIndex (will increment on content toggle)

  $('.button').on('click', function(ev) {
    if ($(this).hasClass('ui-draggable-dragging')) return;
    $($(this).data('content')).css({left: ev.clientX, top: ev.clientY, zIndex: ++z}).toggle();
  });

  $('.content').on('click', function() {
    const $trip = $(this).find('.trip'), tripL = $trip.length;
    this._count |= 0;
    $trip.eq(++this._count % tripL).show().siblings($trip).hide();
  });

});
html,
body {
  height: 100%;
  margin: 0;
}

body {
  background-color: grey;
}

.button {
  width: 30vh;
  height: 30vh;
  background-color: cyan;
}

.content {
  width: 45vh;
  height: 45vh;
  display: none;
  cursor: all-scroll;
  position: absolute;
  background-color: blue;
  color: white;
}

.trip~.trip {
  display: none;
}

[data-content="#content-two"] {background: aquamarine;}
#content-two {background: fuchsia;}
<div class="button draggable" data-content="#content-one">Toggle one</div>
<div class="content draggable" id="content-one">
  <div class="trip">ONE 1</div>
  <div class="trip">ONE 2</div>
  <div class="trip">ONE 3</div>
</div>

<div class="button draggable" data-content="#content-two">Toggle two</div>
<div class="content draggable" id="content-two">
  <div class="trip">TWO 1</div>
  <div class="trip">TWO 2</div>
</div>


<script src="https://code.jquery.com/jquery-1.7.2.min.js"></script>
<script src="https://code.jquery.com/ui/1.8.21/jquery-ui.min.js"></script>
<script src="https://raw.githubusercontent.com/furf/jquery-ui-touch-punch/master/jquery.ui.touch-punch.min.js"></script>

【讨论】:

  • 谢谢!似乎它工作正常!但是:例如,如果我单击 »Toggle one«,则 »ONE 1« 应该位于所有其他对象的顶部。您对此有解决方案吗?
  • @LinaMcClanahan 当然,只需更改为 stack: '.draggable', 并在 CSS 中将您的 .content 设置为最初的z-index:1; :)
  • 嗯好的。如果我单击 »Toggle two« 然后单击»Toggle one«,则 »ONE 1« 不在顶部,但应该在顶部。
  • @LinaMcClanahan 看看。只需引入一个可递增变量z 并将其用作zIndex
  • »可增量变量«? ? 抱歉,我几周前开始编码,我不知道该怎么做:/
【解决方案2】:

为了实现您所追求的订单行为,我建议您对 HTML 结构进行一些更改。您想要的目标是一种“扁平”HTML 结构,以便可拖动元素(即当前嵌套在 #one 和 #two 中的元素)可以相对于彼此进行 z 排序(即在同一包含元素/ DIV)。

完成后,您可以使用draggable() 上的start 事件挂钩来设置“当前位于顶部”的元素。一个简单的方法是引入一个设置 z-index 属性的 CSS 类。

要将可拖动对象定位在被点击的按钮附近,您可以使用 JQuerys position() 方法来获取被点击按钮的顶部/左侧坐标。然后,您可以将它们直接传递给可拖动元素的 css() 方法,如下所示:

  /* Position of this button */
  const position = $(buttonElement).position();

  /* Position target near the button with slight offset */
  draggableElement.css({
    left : position.left + 10,
    top : position.top + 10
  });  

对您的代码进行以下修改应该可以解决问题:

/* 
  Helper function assigns the element as "top most" element
  relative to other elements
  */
function setToTop(element) {

  var zIndexMax = 0;

  $('.content, .button').each(function(i, elem) {

    var zIndex = Number.parseInt($(elem).css('z-index'));
    
    zIndex = Number.isNaN(zIndex) ? 0 : zIndex;

    zIndexMax = Math.max(zIndexMax, zIndex);     
  });
  
  element.css({
    zIndex: zIndexMax + 1
  });
}

$(function() {

  /* Prevent drag from continuing after mouse leaves document */
  $(document).mouseleave(function() {
    $(document).trigger("mouseup")
  });

  $(".content, .button").draggable({
    helper: "original",
    containment: "body",
    start: function(event, ui) {

      /* 
      ui.helper is the element that we're starting to drag 
      */
      setToTop(ui.helper);
    }
  });

  $('.trip').not(':first').hide();
});

$('.button').on('mouseup', function() {

  /* Cause clicked button to come to front */
  setToTop($(this));

  if (!$(this).hasClass('ui-draggable-dragging')) {

    var toggleTarget = $(".content" + $(this).data("target"));

    toggleTarget.toggle();

    if (toggleTarget.is(':visible')) {

      /* Cause newly toggled element to be visible on top */
      setToTop(toggleTarget);

      /* Position of this button */
      const position = $(this).position();

      /* Position target near the button with slight offset */
      toggleTarget.css({
        left: position.left + 10,
        top: position.top + 10
      });
    }
  }
});

$('.content').on('mouseup', function() {

  if (!$(this).hasClass('ui-draggable-dragging')) {

    let trip = $('.trip:visible', this);
    let next = trip.next().length === 0 ? $('.trip:first', this) : trip.next();
    trip.hide();
    next.show();
  }
});
body,
html {
  position: absolute;
  padding: 0;
  margin: 0;
  width: 100%;
  overflow-x: hidden;
  overflow-y: inherit;
  cursor: default;
}

#content {
  max-width: 100vw;
  height: 150vh;
}

.content {
  display: none;
  cursor: all-scroll;
  position: absolute;
  top: 20px;
  left: 20px;
  width: 200px;
  height: 200px;
  background-color: green;
  color: white;
}

.content.one {
  top: 10%;
  left: 10%;
}

.content.two {
  background-color: green;
  color: white;
}

.trip {
  width: 200px;
  height: 200px;
  background-color: blue;
  color: white;
}

.button {
  width: 100px;
  height: 100px;
  position: absolute;
}

#two {
  left: 15%;
  top: 15%;
  background-color: darkgrey;
}

#one {
  left: 5%;
  top: 5%;
  background-color: cyan;
}
<div id="content">

  <div id="one" class="button" data-target=".one">Button 1</div>
  <div id="two" class="button" data-target=".two">Button 2</div>

  <div class="content two">Hey</div>

  <div class="content one">
    <div class="trip">div 1</div>
    <div class="trip">div 2</div>
    <div class="trip">div 3</div>
  </div>

</div>

<script src="https://code.jquery.com/jquery-1.7.2.min.js"></script>
<script src="https://code.jquery.com/ui/1.8.21/jquery-ui.min.js"></script>
<script src="https://raw.githubusercontent.com/furf/jquery-ui-touch-punch/master/jquery.ui.touch-punch.min.js"></script>

更新

为了防止在拖动过程中鼠标离开文档后继续出现故障拖动行为,您可以这样做:

/* 
  Helper function assigns the element as "top most" element
  relative to other elements
*/
function setToTop(element) {

  var zIndexMax = 0;

  $('.content, .button').each(function(i, elem) {

    var zIndex = Number.parseInt($(elem).css('z-index'));        
    zIndex = Number.isNaN(zIndex) ? 0 : zIndex;
    zIndexMax = Math.max(zIndexMax, zIndex);     
  });

  element.css({
    zIndex: zIndexMax + 1
  });
}

【讨论】:

  • 谢谢@DacreDenny!工作正常。你也有关于那个距离的想法吗?
  • @LinaMcClanahan 当然 - 刚刚添加了 :)
  • 啊啊啊!!!我现在很开心!太棒了! ?
  • 您好,我之所以写 Rokos 代码效果更好是因为以下问题:例如,如果您单击 »Button 2«,然后单击 »Button 1«,那么您会带来 »Hey«- div 到顶部,然后是 »Button«,然后是 »Hey«,z-index 无法正常工作。你有解决方案吗? :)
  • @LinaMcClanahan 啊对 - 抱歉,我没有非常密切地关注你的 convo - 我只是做了一个小调整,将 setToTop($(this)) 添加到 mouseup 事件的开头 - 是否可以作为现在需要吗?
猜你喜欢
  • 2011-11-20
  • 1970-01-01
  • 1970-01-01
  • 2012-04-19
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-03-31
  • 1970-01-01
相关资源
最近更新 更多