防止点击事件(如果拖动)

时间:2020-01-28 21:42:44

标签: javascript html

我问了一个相关的问题here

如果要拖动,我正在尝试停止点击事件。

我认为最简单的方法就是拖延自己。基本上,如果用户按下,然后移动,然后释放,则我不想单击事件。

请注意,下面的代码并非试图允许点击,而只是试图阻止它。我以为在preventDefault中调用mouseup会告诉浏览器,不执行默认操作,因为用户松开了鼠标,正在发送click事件。

let dragTarget;
let dragMouseStartX;
let dragMouseStartY;
let dragTargetStartX;
let dragTargetStartY;

const px = v => `${v}px`;

function dragStart(e) {
  e.preventDefault();
  e.stopPropagation();
  dragTarget = this;
  const rect = this.getBoundingClientRect();
  dragMouseStartX = e.pageX;
  dragMouseStartY = e.pageY;
  dragTargetStartX = (window.scrollX + rect.left) | 0; 
  dragTargetStartY = (window.scrollY + rect.top) | 0; 

  window.addEventListener('mousemove', dragMove, {passive: false});
  window.addEventListener('mouseup', dragStop, {passive: false});
}

function dragMove(e) {
  if (dragTarget) {
    e.preventDefault();
    e.stopPropagation();
    const x = dragTargetStartX + (e.pageX - dragMouseStartX);
    const y = dragTargetStartY + (e.pageY - dragMouseStartY);
    dragTarget.style.left = px(x);
    dragTarget.style.top = px(y);
  }
}

function dragStop(e) {
  e.preventDefault();
  e.stopPropagation();
  dragTarget = undefined;
  window.removeEventListener('mousemove', dragMove);
  window.removeEventListener('mouseup', dragStop);
}

document.querySelector('.drag').addEventListener('mousedown', dragStart);
document.querySelector('.drag').addEventListener('click', () => {
  console.log('clicked', new Date());
});
body { height: 100vh; }
.drag { 
  background: red;
  color: white;
  padding: 1em;
  position: absolute;
  user-select: none;
  cursor: pointer;
}
<div class="drag">drag and release me</div>

一种解决方案是删除click事件,然后自己在mouseup中进行。如果没有动静电话,那我要打电话给我打电话

但是,在我的实际用例中,拖动是在父级上进行的(您可以拖动红色或蓝色)

let dragTarget;
let dragMouseStartX;
let dragMouseStartY;
let dragTargetStartX;
let dragTargetStartY;

const px = v => `${v}px`;

function dragStart(e) {
  e.preventDefault();
  e.stopPropagation();
  dragTarget = this;
  const rect = this.getBoundingClientRect();
  dragMouseStartX = e.pageX;
  dragMouseStartY = e.pageY;
  dragTargetStartX = (window.scrollX + rect.left) | 0; 
  dragTargetStartY = (window.scrollY + rect.top) | 0; 

  window.addEventListener('mousemove', dragMove, {passive: false});
  window.addEventListener('mouseup', dragStop, {passive: false});
}

function dragMove(e) {
  if (dragTarget) {
    e.preventDefault();
    e.stopPropagation();
    const x = dragTargetStartX + (e.pageX - dragMouseStartX);
    const y = dragTargetStartY + (e.pageY - dragMouseStartY);
    dragTarget.style.left = px(x);
    dragTarget.style.top = px(y);
  }
}

function dragStop(e) {
  e.preventDefault();
  e.stopPropagation();
  dragTarget = undefined;
  window.removeEventListener('mousemove', dragMove);
  window.removeEventListener('mouseup', dragStop);
}

document.querySelector('.drag').addEventListener('mousedown', dragStart);
document.querySelector('.click').addEventListener('click', () => {
  console.log('clicked', new Date());
});
body { height: 100vh; }
.drag { 
  background: blue;
  color: white;
  padding: 2em;
  position: absolute;
  user-select: none;
  cursor: pointer;
}
.click {
  padding: 1em;
  background: red;
}
<div class="drag"><div class="click">drag and release me</div></div>

因此,现在这2个元素并不直接相关,但是,如果用户拖动红色,则我不希望内部元素发生点击事件。还要注意,在我的真实代码中,我不想以相同的方式接收很多子元素(父元素是拖动目标)。注意:同样,在上面的示例中,我只是尝试停止所有点击事件(调用preventDefault)并失败。

我可以想到很多骇人听闻的解决方案,例如2个。

  • 在第一个mousemove事件中,在所有子级中搜索click事件侦听器,将其全部删除,在mouseup上将其还原(可能在超时后)

  • 在mouseup中,设置一个忽略点击的标志,并设置一个超时以清除该标志,如果设置了该标志,则所有点击侦听器均不操作。

这两个都需要一堆协调。

首先,我需要编写某种系统来跟踪点击处理程序及其所处的元素,以便我可以保存和恢复它们,因此必须使用elem.addEventListener('click', someHandler)而不是registerClickListener(elem, someHandler)elem.addEventListener('click', () => { if (ignoreClicks) return; ... }) 。不难,但是如果我忘记了,那就失败了。

第二秒钟,我必须记住在每个侦听器实现中始终检查一些全局变量。

preventDefault

如果我忘记了,那就失败了。忘记了,我的意思是不相关代码中的DOM更深入。

两者似乎都容易出现半错误,因此想知道是否还有其他我可以忽略的解决方案,就像我认为addEventListener会起作用一样。

我可以包装IF EXISTS (SELECT indname FROM SYSCAT.INDEXES WHERE INDNAME = 'TEST_CREATE_INDEX_OLD') THEN DROP INDEX TEST_CREATE_INDEX_OLD; create index TEST_CREATE_INDEX_NEW on example_table ( id, another_field ); END IF; ,因此对于点击处理程序,它添加了一个包装程序以过滤掉不需要的点击。这样不太容易出错,但是似乎过分了。

我错过了一个更简单的解决方案吗?

2 个答案:

答案 0 :(得分:1)

我认为它是如何工作的,是在同一元素上发生num = string[i + 1].to_i click之后mouseup触发并且不等着看它们做什么(例如,尝试停止点击发生)。

我看到的阻止这种情况发生的最简单方法是在拖动时为该元素禁用指针事件。它在拖动时将光标更改为默认值,虽然这不是最佳选择,但可以避免,但这仍然是我最喜欢的解决方案。例如:

mousedown
let dragTarget;
let dragMouseStartX;
let dragMouseStartY;
let dragTargetStartX;
let dragTargetStartY;

const px = v => `${v}px`;

function dragStart(e) {
  dragTarget = this;
  dragTarget.classList.add("dragging");
  const rect = this.getBoundingClientRect();
  dragMouseStartX = e.pageX;
  dragMouseStartY = e.pageY;
  dragTargetStartX = (window.scrollX + rect.left) | 0; 
  dragTargetStartY = (window.scrollY + rect.top) | 0; 

  window.addEventListener('mousemove', dragMove, {passive: false});
  window.addEventListener('mouseup', dragStop, {passive: false});
  return false;
}

function dragMove(e) {
  if (dragTarget) {
    e.preventDefault();
    e.stopPropagation();
    const x = dragTargetStartX + (e.pageX - dragMouseStartX);
    const y = dragTargetStartY + (e.pageY - dragMouseStartY);
    dragTarget.style.left = px(x);
    dragTarget.style.top = px(y);
  }
}

function dragStop(e) {
  dragTarget.classList.remove("dragging");
  dragTarget = undefined;
  window.removeEventListener('mousemove', dragMove);
  window.removeEventListener('mouseup', dragStop);
}

document.querySelector('.drag').addEventListener('mousedown', dragStart);
document.querySelector('.click').addEventListener('click', () => {
  console.log('clicked', new Date());
});
body { height: 100vh; }
.drag { 
  background: blue;
  color: white;
  padding: 2em;
  position: absolute;
  user-select: none;
  cursor: pointer;
}
.click {
  padding: 1em;
  background: red;
}
.dragging {
  pointer-events: none;
}

您考虑过的其他一些选项当然是可能的,但是在我看来,这是最简单的方法,适用于许多用例。 我从这里的答案得到了这个解决方案的想法: https://stackoverflow.com/a/24273710/12259250 我相信该问题的其他一些答案模仿了您的一些替代方法,因此您也可以检查一下。

答案 1 :(得分:0)

addEventListener有一个可选的第三个参数,称为capture,它指示您的函数在任何其他元素的事件函数之前被调用。通过将其设置为true并应用于您的根元素(窗口),您只需设置一个标志即可关闭所有点击事件。

let ignoreClicks = true; // switch me to turn on click events

document.getElementById ('d1').addEventListener ('click', function() { console.log ('d1'); });
document.getElementById ('d2').addEventListener ('click', function() { console.log ('d2'); });

window.addEventListener ('click', function (event) {
	if (ignoreClicks) event.stopPropagation();
}, true ); 
<div id="d1" style="background-color:red;width:200px;height:100px;"></div>
<div id="d2" style="background-color:green;width:200px;height:100px;"></div>

相关问题