JS 事件侦听器在项目拖动期间停止工作,仅在 pointerup 和随后的 mousemove 之后触发
JS event listeners stop working during item drag, only fire after pointerup and subsequent mousemove
我无法让事件侦听器在实际事件发生时触发。我创建了一个拖放系统,在目标的 pointerover
上设置变量 hoveringOverTarget = true
,在图像上侦听 pointerdown
,然后在 [=14= 上调用函数] 检查它是否被释放到目标上空。
let hoveringOverTarget = false;
const target = document.querySelector('.dragtarget');
if(target) {
target.addEventListener('pointerover', ()=>{
hoveringOverTarget = true;
console.log(hoveringOverTarget);
});
target.addEventListener('pointerleave', ()=>{
hoveringOverTarget = false;
console.log(hoveringOverTarget);
});
}
function beginItemDrag(e) {
console.log('beginItemDrag called');
const item = e.target;
if(target) {
item.addEventListener('pointerup', ()=>{
console.log('pointerup');
releaseItem();
});
} else {
console.log('No .dragtarget on page');
}
}
function releaseItem(e) {
const item = e.target;
if(hoveringOverTarget) {
console.log('YES!!!');
readcard(item);
}
}
document.querySelectorAll('.item').forEach(item=>item.addEventListener('pointerdown', beginItemDrag));
但是,在拖动图像期间,没有其他事件侦听器响应。当将图像拖入和拖出目标区域时,第 4 行和第 8 行的 pointerover
和 pointerleave
事件侦听器 不再触发 (尽管在不拖动时工作正常图像),并且 pointerup
函数不会在 pointerup 上触发。相反,当我释放该项目时,什么也没有发生,除非 鼠标随后移动,即使移动一个像素,此时 pointerover
事件最终触发(hoveringOverTarget
记录为真)并且 pointerup
事件根本不会触发。
通过各种搜索,我看到一些人的问题通过将 e.preventDefault()
添加到事件侦听器来解决。当我这样做时,根本不会触发任何事件。
这是怎么回事?
由于没有其他人能够弄清楚这一点,我将 post 我所做的最终有效的更改。我尝试了各种不同的东西,但我认为我最终的成功主要归功于:
- 将
pointerup
事件侦听器附加到 整个文档 而不是单个项目
- 通过文档范围的变量识别拖动的项目,因此所有函数都可以可靠地访问它(而不是希望
e.target
在从个人的 pointerup 侦听器调用 releaseItem(e)
时是正确的项目项)
- 将
e.preventDefault()
添加到 beginItemDrag()
以停止浏览器的默认图像拖动行为(不同于标准元素拖动行为!!!),这会在拖动过程中自私地阻止其他事件侦听器。
tl:博士;我从函数中提升了变量并使我的事件侦听器更广泛,直到我最终捕获了正确的事件。
let hoveringOverTarget = false;
let draggedItem = null;
const target = document.querySelector('.dragtarget');
if(target) {
target.addEventListener('pointerover', ()=>{
hoveringOverTarget = true;
console.log(hoveringOverTarget);
});
target.addEventListener('pointerleave', ()=>{
hoveringOverTarget = false;
console.log(hoveringOverTarget);
});
}
function beginItemDrag(e) {
e.preventDefault(); // this is CRUCIAL! Disables default image "draggable" functionality
draggedItem = e.target;
document.addEventListener('pointerup', releaseItem);
if(target) target.style.boxShadow = '0 0 20px white, 0 0 40px white';
}
function releaseItem() {
if(target) target.style.boxShadow = 'none';
if(hoveringOverTarget) { readcard(draggedItem); }
document.removeEventListener('pointerup', releaseItem);
}
document.querySelectorAll('.toolboxitem').forEach(item=>item.addEventListener('pointerdown', beginItemDrag));
您似乎找到了一个成功的work-around。不过,以防万一其他人来这里寻找答案,我怀疑这是原始问题的根源:对于允许 direct manipulation (e.g., using a finger to pan or zoom the current page), pointerdown
triggers implicit pointer capture 的触摸屏浏览器,这会导致目标捕获所有后续指针事件,就好像它们正在发生一样在捕捉目标之上。所以 pointerleave
,例如,永远不会触发。这一直持续到捕获在 pointerup
.
之后隐式释放
要解决此问题,您只需在 pointerdown
事件侦听器中释放捕获——此处 beginItemDrag
——如果已设置:
if (e.target.hasPointerCapture(e.pointerId))
e.target.releasePointerCapture(e.pointerId);
我无法让事件侦听器在实际事件发生时触发。我创建了一个拖放系统,在目标的 pointerover
上设置变量 hoveringOverTarget = true
,在图像上侦听 pointerdown
,然后在 [=14= 上调用函数] 检查它是否被释放到目标上空。
let hoveringOverTarget = false;
const target = document.querySelector('.dragtarget');
if(target) {
target.addEventListener('pointerover', ()=>{
hoveringOverTarget = true;
console.log(hoveringOverTarget);
});
target.addEventListener('pointerleave', ()=>{
hoveringOverTarget = false;
console.log(hoveringOverTarget);
});
}
function beginItemDrag(e) {
console.log('beginItemDrag called');
const item = e.target;
if(target) {
item.addEventListener('pointerup', ()=>{
console.log('pointerup');
releaseItem();
});
} else {
console.log('No .dragtarget on page');
}
}
function releaseItem(e) {
const item = e.target;
if(hoveringOverTarget) {
console.log('YES!!!');
readcard(item);
}
}
document.querySelectorAll('.item').forEach(item=>item.addEventListener('pointerdown', beginItemDrag));
但是,在拖动图像期间,没有其他事件侦听器响应。当将图像拖入和拖出目标区域时,第 4 行和第 8 行的 pointerover
和 pointerleave
事件侦听器 不再触发 (尽管在不拖动时工作正常图像),并且 pointerup
函数不会在 pointerup 上触发。相反,当我释放该项目时,什么也没有发生,除非 鼠标随后移动,即使移动一个像素,此时 pointerover
事件最终触发(hoveringOverTarget
记录为真)并且 pointerup
事件根本不会触发。
通过各种搜索,我看到一些人的问题通过将 e.preventDefault()
添加到事件侦听器来解决。当我这样做时,根本不会触发任何事件。
这是怎么回事?
由于没有其他人能够弄清楚这一点,我将 post 我所做的最终有效的更改。我尝试了各种不同的东西,但我认为我最终的成功主要归功于:
- 将
pointerup
事件侦听器附加到 整个文档 而不是单个项目 - 通过文档范围的变量识别拖动的项目,因此所有函数都可以可靠地访问它(而不是希望
e.target
在从个人的 pointerup 侦听器调用releaseItem(e)
时是正确的项目项) - 将
e.preventDefault()
添加到beginItemDrag()
以停止浏览器的默认图像拖动行为(不同于标准元素拖动行为!!!),这会在拖动过程中自私地阻止其他事件侦听器。
tl:博士;我从函数中提升了变量并使我的事件侦听器更广泛,直到我最终捕获了正确的事件。
let hoveringOverTarget = false;
let draggedItem = null;
const target = document.querySelector('.dragtarget');
if(target) {
target.addEventListener('pointerover', ()=>{
hoveringOverTarget = true;
console.log(hoveringOverTarget);
});
target.addEventListener('pointerleave', ()=>{
hoveringOverTarget = false;
console.log(hoveringOverTarget);
});
}
function beginItemDrag(e) {
e.preventDefault(); // this is CRUCIAL! Disables default image "draggable" functionality
draggedItem = e.target;
document.addEventListener('pointerup', releaseItem);
if(target) target.style.boxShadow = '0 0 20px white, 0 0 40px white';
}
function releaseItem() {
if(target) target.style.boxShadow = 'none';
if(hoveringOverTarget) { readcard(draggedItem); }
document.removeEventListener('pointerup', releaseItem);
}
document.querySelectorAll('.toolboxitem').forEach(item=>item.addEventListener('pointerdown', beginItemDrag));
您似乎找到了一个成功的work-around。不过,以防万一其他人来这里寻找答案,我怀疑这是原始问题的根源:对于允许 direct manipulation (e.g., using a finger to pan or zoom the current page), pointerdown
triggers implicit pointer capture 的触摸屏浏览器,这会导致目标捕获所有后续指针事件,就好像它们正在发生一样在捕捉目标之上。所以 pointerleave
,例如,永远不会触发。这一直持续到捕获在 pointerup
.
要解决此问题,您只需在 pointerdown
事件侦听器中释放捕获——此处 beginItemDrag
——如果已设置:
if (e.target.hasPointerCapture(e.pointerId))
e.target.releasePointerCapture(e.pointerId);