PointerEvents:检测触摸 "through" 元素
PointerEvents: Detect touching "through" an element
使用指针事件,我找不到正确的事件来触发智能手机上基于手指的触摸(使用 Chrome Android 和 Chrome Devtools 进行了移动仿真测试) .
我需要的是:一个 "hover" 事件,如果你触摸动作 通过 一个元素,同时按住手指在屏幕上移动。
即手指在元素外向下,移动穿过元素,完全穿过元素后才向上移动手指。
我附上了一个代码片段以明确:我不需要蓝色元素的事件,我只需要片段中红色元素的相应 "in/out" 事件。示例 JS 代码将为鼠标触发,但在移动设备上它不会触发任何 console.infos.
var elem = document.querySelector(".element");
elem.addEventListener("pointerover", function() {
console.clear();
console.info("pointerover triggered");
});
elem.addEventListener("pointerenter", function() {
console.clear();
console.info("pointerenter triggered");
});
elem.addEventListener("pointerleave", function() {
console.clear();
console.info("pointerleave triggered");
});
.outer {
width: 100px;
height: 100px;
border: 3px solid grey;
font-size: 12px;
color: white;
text-align:center;
touch-action: none;
}
.start {
position: relative;
top:0px;
left:0px;
width: 100px;
height: 20px;
background-color: blue;
}
.element {
position: relative;
top: 20px;
left: 0px;
width: 100px;
height: 20px;
background-color: red;
}
.end {
position: relative;
top: 40px;
right: 0;
width: 100px;
height: 20px;
background-color: blue;
}
<div class="outer">
<div class="start">Start touch here</div>
<div class="element">Move over here</div>
<div class="end">End touch here</div>
</div>
试试这个
<script>
var startElem = document.querySelector(".start");
var endElem = document.querySelector(".end");
var elem = document.querySelector(".element");
var started = false;
var passedThroughStart = false;
var passedThroughEnd = false;
var ended = false;
startElem.addEventListener("pointerdown", function(e){
started = true;
});
window.addEventListener("pointermove", function(e) {
var x = e.clientX;
var y = e.clientY;
var bounds = elem.getBoundingClientRect();
if( !passedThroughStart &&
x > bounds.left && x < bounds.left + bounds.width &&
y > bounds.top && y < bounds.top + bounds.height
){
passedThroughStart = true;
}
if( passedThroughStart && !passedThroughEnd &&
x > bounds.left && x < bounds.left + bounds.width &&
y > bounds.top + bounds.height
){
passedThroughEnd = true;
}
})
window.addEventListener("pointerup", function(e) {
var x = e.clientX;
var y = e.clientY;
var bounds = endElem.getBoundingClientRect();
ended = ( x > bounds.left && x < bounds.left + bounds.width && y > bounds.top && y < bounds.top + bounds.height)
if( started && passedThroughStart && passedThroughEnd && ended ){
console.log("Hooray!");
}
started = false;
passedThroughStart = false;
passedThroughEnd = false;
ended = false;
});
</script>
或者使用 pointerenter
和 pointerleave
而不是 pointermove
elem.addEventListener('pointenter', function(e) {
passedThroughStart = true;
}
elem.addEventListener('pointleave', function(e) {
passedThroughEnd = true;
}
希望我理解正确。我为您编写并测试了两种不同的解决方案:指针事件和触摸事件。在此事件的每个移动事件中,您可以使用函数 document.elementFromPoint()
.
检测当前元素
指针事件的解决方案
也许你可以使用 pointerevents – 它们可以在 Chrome Devtools 中使用移动仿真,但不能在 my Android 设备上使用(我觉得我的设备太旧了)。或者你可以将它与 Pointer Events Polyfill 一起使用。您可以看到指针事件的浏览器兼容性 here.
var elementFromPoint,
isFingerDown = false,
isThroughElemMoved = false,
elem = document.querySelector('.element'),
output = document.querySelector('#output');
document.addEventListener('pointerdown', function(e)
{
if(elem != e.target)
{
isFingerDown = true;
output.innerHTML = 'pointer-START';
}
});
document.addEventListener('pointermove', function(e)
{
elementFromPoint = document.elementFromPoint(e.pageX - window.pageXOffset, e.pageY - window.pageYOffset);
if(elem == elementFromPoint)
{
isThroughElemMoved = true;
output.innerHTML = 'pointer-MOVE';
}
});
document.addEventListener('pointerup', function(e)
{
if(isFingerDown && isThroughElemMoved && elem != elementFromPoint)
output.innerHTML = 'It is done!';
isFingerDown = isThroughElemMoved = false;
});
.outer
{
width: 100px;
height: 100px;
border: 3px solid grey;
font-size: 12px;
color: white;
text-align: center;
/*touch-action: none*/
}
.outer div{position: relative; left: 0; height: 20px}
.start{top: 0; background: blue}
.element{top: 20px; background: red}
.end{top: 40px; background: blue}
<div class="outer">
<div class="start">Start touch here</div>
<div class="element">Move over here</div>
<div class="end">End touch here</div>
</div>
<br><br>
<div id="output">info</div>
有触摸事件的解决方案
但是您也可以使用 touch events。不幸的是,事件 touchenter
和 touchleave
已从规范中删除,因此我们也必须使用 document.elementFromPoint()
编写解决方法。
以下代码片段仅适用于移动仿真(使用 Chrome Devtools 测试)或支持触摸事件的设备(使用 Android 测试)。
var elementFromPoint,
isFingerDown = false,
isThroughElemMoved = false,
elem = document.querySelector('.element'),
output = document.querySelector('#output');
document.addEventListener('touchstart', function(e)
{
if(elem != e.target)
{
isFingerDown = true;
output.innerHTML = 'touch-START';
}
});
document.addEventListener('touchmove', function(e)
{
var touch = e.touches[0];
elementFromPoint = document.elementFromPoint(touch.pageX - window.pageXOffset, touch.pageY - window.pageYOffset);
if(elem == elementFromPoint)
{
isThroughElemMoved = true;
output.innerHTML = 'touch-MOVE';
}
});
document.addEventListener('touchend', function(e)
{
if(isFingerDown && isThroughElemMoved && elem != elementFromPoint)
output.innerHTML = 'It is done!';
isFingerDown = isThroughElemMoved = false;
});
.outer
{
width: 100px;
height: 100px;
border: 3px solid grey;
font-size: 12px;
color: white;
text-align: center;
/*touch-action: none*/
}
.outer div{position: relative; left: 0; height: 20px}
.start{top: 0; background: blue}
.element{top: 20px; background: red}
.end{top: 40px; background: blue}
<div class="outer">
<div class="start">Start touch here</div>
<div class="element">Move over here</div>
<div class="end">End touch here</div>
</div>
<br><br>
<div id="output">info</div>
也许以下链接可以帮到您:
- Get element from point when you have overlapping elements?
- 如何找出touchmove的实际event.target javascript
事件?
使用指针事件,我找不到正确的事件来触发智能手机上基于手指的触摸(使用 Chrome Android 和 Chrome Devtools 进行了移动仿真测试) .
我需要的是:一个 "hover" 事件,如果你触摸动作 通过 一个元素,同时按住手指在屏幕上移动。
即手指在元素外向下,移动穿过元素,完全穿过元素后才向上移动手指。
我附上了一个代码片段以明确:我不需要蓝色元素的事件,我只需要片段中红色元素的相应 "in/out" 事件。示例 JS 代码将为鼠标触发,但在移动设备上它不会触发任何 console.infos.
var elem = document.querySelector(".element");
elem.addEventListener("pointerover", function() {
console.clear();
console.info("pointerover triggered");
});
elem.addEventListener("pointerenter", function() {
console.clear();
console.info("pointerenter triggered");
});
elem.addEventListener("pointerleave", function() {
console.clear();
console.info("pointerleave triggered");
});
.outer {
width: 100px;
height: 100px;
border: 3px solid grey;
font-size: 12px;
color: white;
text-align:center;
touch-action: none;
}
.start {
position: relative;
top:0px;
left:0px;
width: 100px;
height: 20px;
background-color: blue;
}
.element {
position: relative;
top: 20px;
left: 0px;
width: 100px;
height: 20px;
background-color: red;
}
.end {
position: relative;
top: 40px;
right: 0;
width: 100px;
height: 20px;
background-color: blue;
}
<div class="outer">
<div class="start">Start touch here</div>
<div class="element">Move over here</div>
<div class="end">End touch here</div>
</div>
试试这个
<script>
var startElem = document.querySelector(".start");
var endElem = document.querySelector(".end");
var elem = document.querySelector(".element");
var started = false;
var passedThroughStart = false;
var passedThroughEnd = false;
var ended = false;
startElem.addEventListener("pointerdown", function(e){
started = true;
});
window.addEventListener("pointermove", function(e) {
var x = e.clientX;
var y = e.clientY;
var bounds = elem.getBoundingClientRect();
if( !passedThroughStart &&
x > bounds.left && x < bounds.left + bounds.width &&
y > bounds.top && y < bounds.top + bounds.height
){
passedThroughStart = true;
}
if( passedThroughStart && !passedThroughEnd &&
x > bounds.left && x < bounds.left + bounds.width &&
y > bounds.top + bounds.height
){
passedThroughEnd = true;
}
})
window.addEventListener("pointerup", function(e) {
var x = e.clientX;
var y = e.clientY;
var bounds = endElem.getBoundingClientRect();
ended = ( x > bounds.left && x < bounds.left + bounds.width && y > bounds.top && y < bounds.top + bounds.height)
if( started && passedThroughStart && passedThroughEnd && ended ){
console.log("Hooray!");
}
started = false;
passedThroughStart = false;
passedThroughEnd = false;
ended = false;
});
</script>
或者使用 pointerenter
和 pointerleave
而不是 pointermove
elem.addEventListener('pointenter', function(e) {
passedThroughStart = true;
}
elem.addEventListener('pointleave', function(e) {
passedThroughEnd = true;
}
希望我理解正确。我为您编写并测试了两种不同的解决方案:指针事件和触摸事件。在此事件的每个移动事件中,您可以使用函数 document.elementFromPoint()
.
指针事件的解决方案
也许你可以使用 pointerevents – 它们可以在 Chrome Devtools 中使用移动仿真,但不能在 my Android 设备上使用(我觉得我的设备太旧了)。或者你可以将它与 Pointer Events Polyfill 一起使用。您可以看到指针事件的浏览器兼容性 here.
var elementFromPoint,
isFingerDown = false,
isThroughElemMoved = false,
elem = document.querySelector('.element'),
output = document.querySelector('#output');
document.addEventListener('pointerdown', function(e)
{
if(elem != e.target)
{
isFingerDown = true;
output.innerHTML = 'pointer-START';
}
});
document.addEventListener('pointermove', function(e)
{
elementFromPoint = document.elementFromPoint(e.pageX - window.pageXOffset, e.pageY - window.pageYOffset);
if(elem == elementFromPoint)
{
isThroughElemMoved = true;
output.innerHTML = 'pointer-MOVE';
}
});
document.addEventListener('pointerup', function(e)
{
if(isFingerDown && isThroughElemMoved && elem != elementFromPoint)
output.innerHTML = 'It is done!';
isFingerDown = isThroughElemMoved = false;
});
.outer
{
width: 100px;
height: 100px;
border: 3px solid grey;
font-size: 12px;
color: white;
text-align: center;
/*touch-action: none*/
}
.outer div{position: relative; left: 0; height: 20px}
.start{top: 0; background: blue}
.element{top: 20px; background: red}
.end{top: 40px; background: blue}
<div class="outer">
<div class="start">Start touch here</div>
<div class="element">Move over here</div>
<div class="end">End touch here</div>
</div>
<br><br>
<div id="output">info</div>
有触摸事件的解决方案
但是您也可以使用 touch events。不幸的是,事件 touchenter
和 touchleave
已从规范中删除,因此我们也必须使用 document.elementFromPoint()
编写解决方法。
以下代码片段仅适用于移动仿真(使用 Chrome Devtools 测试)或支持触摸事件的设备(使用 Android 测试)。
var elementFromPoint,
isFingerDown = false,
isThroughElemMoved = false,
elem = document.querySelector('.element'),
output = document.querySelector('#output');
document.addEventListener('touchstart', function(e)
{
if(elem != e.target)
{
isFingerDown = true;
output.innerHTML = 'touch-START';
}
});
document.addEventListener('touchmove', function(e)
{
var touch = e.touches[0];
elementFromPoint = document.elementFromPoint(touch.pageX - window.pageXOffset, touch.pageY - window.pageYOffset);
if(elem == elementFromPoint)
{
isThroughElemMoved = true;
output.innerHTML = 'touch-MOVE';
}
});
document.addEventListener('touchend', function(e)
{
if(isFingerDown && isThroughElemMoved && elem != elementFromPoint)
output.innerHTML = 'It is done!';
isFingerDown = isThroughElemMoved = false;
});
.outer
{
width: 100px;
height: 100px;
border: 3px solid grey;
font-size: 12px;
color: white;
text-align: center;
/*touch-action: none*/
}
.outer div{position: relative; left: 0; height: 20px}
.start{top: 0; background: blue}
.element{top: 20px; background: red}
.end{top: 40px; background: blue}
<div class="outer">
<div class="start">Start touch here</div>
<div class="element">Move over here</div>
<div class="end">End touch here</div>
</div>
<br><br>
<div id="output">info</div>
也许以下链接可以帮到您:
- Get element from point when you have overlapping elements?
- 如何找出touchmove的实际event.target javascript 事件?