gpt4 book ai didi

javascript - 如果拖动则阻止单击事件

转载 作者:行者123 更新时间:2023-12-02 21:57:56 25 4
gpt4 key购买 nike

我问了一个相关问题here

我正在尝试在拖动时停止点击事件。

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

请注意,下面的代码并不试图允许点击,它只是试图阻止它。我认为在 mouseup 中调用 preventDefault 会告诉浏览器,不要执行默认操作,即发送 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>

一种解决方案是删除点击事件并在 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>

所以现在这两个元素不直接相关,但是,如果用户拖动红色,我不希望内部元素获得单击事件。另请注意,在我的实际代码中,有很多子元素我不想以相同的方式接收单击事件(父元素是拖动目标)。注意:同样,在上面的示例中,我只是尝试停止所有点击事件(调用 PreventDefault)并失败。

我能想到很多 hacky 解决方案,例如 2 个。

  • 在第一个 mousemove 事件中,搜索所有子级的单击事件监听器,删除所有监听器,在 mouseup 时恢复它们(可能在超时后)

  • 在 mouseup 中,设置一个标志来忽略点击,并设置一个超时来清除该标志,如果设置了该标志,则所有点击监听器均不执行任何操作。

这两者都需要大量的协调。

首先,我需要编写某种系统来跟踪单击处理程序及其所在的元素,以便我可以保存和恢复它们,而不是 elem.addEventListener('click', someHandler) 它必须更像 registerClickListener(elem, someHandler)。不难,但如果我忘记了,就会失败。

在第二个中,我必须记住始终检查每个监听器实现中的某些全局变量。

elem.addEventListener('click', () => {
if (ignoreClicks) return;
...
})

如果我忘记了,那么它就会失败。我所说的“忘记”是指在 DOM 中更深入的不相关代码中。

两者似乎都容易出错,所以想知道是否还有其他我忽略的解决方案,就像我认为 preventDefault 一样有效。

我可以包装addEventListener,这样对于点击处理程序,它会添加一个包装器来过滤掉不需要的点击。这不太容易出错,但似乎有点矫枉过正。

我是否缺少一个更简单的解决方案?

最佳答案

我认为它的工作原理是 click 在同一元素上发生 mouseupmousedown 后触发,并且不等待查看他们做了什么(例如试图阻止点击发生)。

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

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;
}
<div class="drag"><div class="click">drag and release me</div></div>

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

关于javascript - 如果拖动则阻止单击事件,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59957474/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com