【问题标题】:prevent click on hyperlink while dragging/holding防止在拖动/按住时单击超链接
【发布时间】:2018-12-10 02:08:57
【问题描述】:

我有带有锚元素的项目 div 元素作为子元素。锚子项的大小会拉伸父项元素。

我已使用库 interact.js 使项目元素可拖动。当它们保持 300 毫秒或更长时间时,这些项目变得可拖动。问题是,当释放拖动时,子项的锚链接会被触发。

如何防止子元素在父元素被按住/拖动时触发超链接?

这是问题的一个小例子

let items = document.getElementsByClassName("item");

// add class .draggable to each item
for(var i = 0; i < items.length; i++)
{
   items[i].classList.add("draggable");
}

// target elements with the "draggable" class
interact('.draggable').draggable({
	autoScroll: true,
	hold: 300,
	// call this function on every dragmove event
	onmove: dragMoveListener,
	// call this function on every dragend event
	onend: function (event) {
		var target = event.target;
		target.style.webkitTransform =
		target.style.transform =
		'translate(0px, 0px)';

		target.setAttribute('data-x', 0);
		target.setAttribute('data-y', 0);
	}
});

// this function is calles on every dragmove event
function dragMoveListener (event) {
	var target = event.target,
		 // keep the dragged position in the data-x/data-y attributes
		 x = (parseFloat(target.getAttribute('data-x')) || 0) + event.dx,
		 y = (parseFloat(target.getAttribute('data-y')) || 0) + event.dy;

	// translate the element
	target.style.webkitTransform =
		target.style.transform =
		'translate(' + x + 'px, ' + y + 'px)';

	// update the posiion attributes
	target.setAttribute('data-x', x);
	target.setAttribute('data-y', y);
};



interact('.dropzone').dropzone({

	
  ondropactivate: function (event) {
    event.target.classList.add('drop-active');
  },
	
  ondragenter: function (event) {
	  var draggableElement = event.relatedTarget,
			dropzoneElement = event.target;

	  // feedback the possibility of a drop
	  dropzoneElement.classList.add('drop-target');
	  draggableElement.classList.add('can-drop');
  },
	
  ondragleave: function (event) {
	  // remove the drop feedback style
	  event.target.classList.remove('drop-target');
	  event.relatedTarget.classList.remove('can-drop');
  },
	
  ondrop: function (event) {
	  //delete Bookmark here!
	  event.relatedTarget.classList.add('drop-ok');
  },
	
  ondropdeactivate: function (event) {
	  // remove active dropzone feedback
	  event.target.classList.remove('drop-active');
	  event.target.classList.remove('drop-target');
  }
});
body {
  background-color: #EDEFF3;
  padding: 40px 48px;
}

.item {
  display: inline-block;
  margin: 8px;
  background-color: RGBA(255, 255, 255, 1);
  -webkit-user-select: none;
     -moz-user-select: none;
      -ms-user-select: none;
          user-select: none;
  border-radius: 10px;
  z-index: 999;
}
.item a {
  position: relative;
  display: inline-block;
  border-radius: 10px;
  line-height: 40px;
  padding: 0 32px 0 48px;
  font-weight: 400;
  text-decoration: none;
  font-size: 13px;
  color: black;
  font-size: 14px;
}
.item a .dott {
  position: absolute;
  top: 12px;
  left: 20px;
  height: 16px;
  width: 16px;
  background-color: tomato;
  border-radius: 100%;
}
.item.can-drop a {
  text-decoration: line-through;
}
.item.drop-ok {
  display: none;
}

.category {
  display: flex;
  flex-wrap: wrap;
  position: relative;
  align-items: flex-start;
  background-color: RGBA(127, 135, 147, 0.2);
  margin: 16px;
  padding: 8px;
}

.dropzone {
  height: 20%;
  width: 100%;
  position: fixed;
  bottom: 0;
  left: 0;
  background-color: tomato;
  opacity: 0;
}
.dropzone.drop-active {
  opacity: 1;
}
.dropzone.drop-target {
  background-color: #F15B52;
}
<script src="https://cdn.jsdelivr.net/npm/interactjs@1.3.4/dist/interact.min.js"></script>
<div class="category">
	
	<div class="item">
		<a href="https://www.google.com/"><span class="dott"></span>bookmark</a>
	</div>
	
	<div class="item">
		<a href="https://www.google.com/">
			<span class="dott"></span>
		bookmark</a>
	</div>
	
	<div class="item">
		<a href="https://www.google.com/"><span class="dott"></span>bookmark</a>
	</div>
	
	<div class="item">
		<a href="https://www.google.com/"><span class="dott"></span>bookmark</a>
	</div>
	
	<div class="item">
		<a href="https://www.google.com/"><span class="dott"></span>bookmark</a>
	</div>	
</div>

<div class="dropzone"></div>

这是我目前在 Codepen 的状态: https://codepen.io/iamrbn/pen/pKGPMz

【问题讨论】:

  • 寻求调试帮助的问题(“为什么这段代码不起作用?”)必须包括所需的行为、特定的问题或错误以及重现它所需的最短代码 问题本身
  • 我修复了代码示例的断开链接
  • 很好,仍然适用minimal reproducible example
  • 感谢您提供示例代码。现在我们可以帮助您:)
  • @www139 问题仍然没有可验证的样本,并且指向外部资源的链接不算数,因为当该链接死亡时,此问题的价值也会如此/答案

标签: javascript hyperlink draggable preventdefault interact.js


【解决方案1】:

也许不是最优雅的解决方案,但它确实有效。我的第一次尝试失败了,但我认为我现在有一些可行的方法。我创建了一个标志系统来跟踪事件。请注意,我将onstart 添加到可拖动实例中。我不得不添加一个 300 毫秒的超时来匹配保持的时间。尽管保持了 300 毫秒,但似乎在鼠标按下时立即触发了 onstart。我不确定你图书馆的那部分是如何工作的;)

无论如何,等待 300 毫秒,然后设置拖动标志。请注意,该变量是全局变量以供参考。在实施此之前检查您的项目变量范围。您可能想要创建一个公共对象来防止全局混淆。

我为每个链接添加了一个点击事件监听器。当点击触发时,检查保持标志状态。如果是拖拽,则阻止该事件。否则,继续注册点击。注意:我尝试将此标志评估器代码添加到可拖动实例中的 onend 方法,但onend 原来是mouseup 事件,它在click 之前触发。因此,评估需要通过click 事件进行。在范围内执行此操作的最佳方法是向每个链接添加 click 事件。

哇!天哪,这大概花了一个小时。让我知道它是否有效:)

let items = document.getElementsByClassName("item");

// add class .draggable to each item
for (var i = 0; i < items.length; i++) {
  items[i].classList.add("draggable");
  items[i].children[0].addEventListener('click',function(e){
  if(drag){
    drag = false;
    e.preventDefault()
    }
  });
}

var drag = false;

// target elements with the "draggable" class
interact('.draggable').draggable({
  autoScroll: true,
  hold: 300,
  // call this function on every dragmove event
  onstart: function(){
    setTimeout(function(){
      drag = true;
    },300);
  },
  onmove: dragMoveListener,
  // call this function on every dragend event
  onend: function(event) {
  
    var target = event.target;
    target.style.webkitTransform =
      target.style.transform =
      'translate(0px, 0px)';

    target.setAttribute('data-x', 0);
    target.setAttribute('data-y', 0);
  }
});

// this function is calles on every dragmove event
function dragMoveListener(event) {
  var target = event.target,
    // keep the dragged position in the data-x/data-y attributes
    x = (parseFloat(target.getAttribute('data-x')) || 0) + event.dx,
    y = (parseFloat(target.getAttribute('data-y')) || 0) + event.dy;

  // translate the element
  target.style.webkitTransform =
    target.style.transform =
    'translate(' + x + 'px, ' + y + 'px)';

  // update the posiion attributes
  target.setAttribute('data-x', x);
  target.setAttribute('data-y', y);
};



interact('.dropzone').dropzone({


  ondropactivate: function(event) {
    event.target.classList.add('drop-active');
  },

  ondragenter: function(event) {
    var draggableElement = event.relatedTarget,
      dropzoneElement = event.target;

    // feedback the possibility of a drop
    dropzoneElement.classList.add('drop-target');
    draggableElement.classList.add('can-drop');
  },

  ondragleave: function(event) {
    // remove the drop feedback style
    event.target.classList.remove('drop-target');
    event.relatedTarget.classList.remove('can-drop');
  },

  ondrop: function(event) {
    //delete Bookmark here!
    event.relatedTarget.classList.add('drop-ok');
  },

  ondropdeactivate: function(event) {
    // remove active dropzone feedback
    event.target.classList.remove('drop-active');
    event.target.classList.remove('drop-target');
  }
});
body {
  background-color: #EDEFF3;
  padding: 40px 48px;
}

.item {
  display: inline-block;
  margin: 8px;
  background-color: RGBA(255, 255, 255, 1);
  -webkit-user-select: none;
  -moz-user-select: none;
  -ms-user-select: none;
  user-select: none;
  border-radius: 10px;
  z-index: 999;
}

.item a {
  position: relative;
  display: inline-block;
  border-radius: 10px;
  line-height: 40px;
  padding: 0 32px 0 48px;
  font-weight: 400;
  text-decoration: none;
  font-size: 13px;
  color: black;
  font-size: 14px;
}

.item a .dott {
  position: absolute;
  top: 12px;
  left: 20px;
  height: 16px;
  width: 16px;
  background-color: tomato;
  border-radius: 100%;
}

.item.can-drop a {
  text-decoration: line-through;
}

.item.drop-ok {
  display: none;
}

.category {
  display: flex;
  flex-wrap: wrap;
  position: relative;
  align-items: flex-start;
  background-color: RGBA(127, 135, 147, 0.2);
  margin: 16px;
  padding: 8px;
}

.dropzone {
  height: 20%;
  width: 100%;
  position: fixed;
  bottom: 0;
  left: 0;
  background-color: tomato;
  opacity: 0;
}

.dropzone.drop-active {
  opacity: 1;
}

.dropzone.drop-target {
  background-color: #F15B52;
}
<script src="https://cdn.jsdelivr.net/npm/interactjs@1.3.4/dist/interact.min.js"></script>
<div class="category">

  <div class="item">
    <a href="https://www.google.com/"><span class="dott"></span>bookmark</a>
  </div>

  <div class="item">
    <a href="https://www.google.com/">
      <span class="dott"></span> bookmark
    </a>
  </div>

  <div class="item">
    <a href="https://www.google.com/"><span class="dott"></span>bookmark</a>
  </div>

  <div class="item">
    <a href="https://www.google.com/"><span class="dott"></span>bookmark</a>
  </div>

  <div class="item">
    <a href="https://www.google.com/"><span class="dott"></span>bookmark</a>
  </div>
</div>

<div class="dropzone"></div>

【讨论】:

  • 我喜欢这个解决方案背后的想法,谢谢!但是超链接现在不会在正常点击时触发。你知道为什么吗?
  • 可能是点击后留下了类?您在什么情况下单击链接而没有工作?即,当您尝试点击时链接在哪里?
  • 不拖动项目,刷新页面后,只有元素上的可拖动和项目类,正常单击不会触发我的浏览器中的超链接。您的浏览器是否有其他行为?
  • 哦,我现在明白了。你说得对。这是因为item draggable 类始终存在。不过,我有另一个想法。我可以看看data-x和data-y是否等于0。如果不是,则阻止点击。
  • 哦,非常感谢您的帮助!这就像一个魅力:) 感谢您的帮助和您为解决方案所花费的时间!
猜你喜欢
  • 1970-01-01
  • 2022-07-15
  • 2014-04-07
  • 2013-02-11
  • 1970-01-01
  • 1970-01-01
  • 2019-05-20
  • 1970-01-01
  • 2018-07-24
相关资源
最近更新 更多