"pointermove"事件无法与触摸配合使用.为什么不? [英] `pointermove` event not working with touch. Why not?
问题描述
我有这支笔:
https://codepen.io/anon/pen/eyKeqK
如果您在触摸屏设备上进行尝试(例如,通过手机上的笔 ),您会注意到,拖动时,白光(小球)仅移动了一点点,然后停止工作.
If you try it on a touch-screen device (f.e. visit the pen on your phone) you'll notice that when you drag, the white light (the little sphere) only moves for a tiny bit then it stops working.
移动的逻辑在pointermove
事件处理程序中.使用鼠标(而不是触摸),它可以在桌面上正常工作.
The logic for the movement is in the pointermove
event handler. It works fine on Desktop using a mouse, just not with touch.
我们如何解决此问题,以使光线在触摸拖动时保持移动(不只是一小会儿),并且作为奖励,我们如何防止下拉时刷新页面?
How do we fix this so the light keeps moving while touch dragging (not just for a moment), and as bonus how do we prevent it from refreshing the page when we pull down?
这是笔的代码:
HTML(精简版):
/! Made with http://github.com/trusktr/infamous
script src="https://cdn.rawgit.com/trusktr/e37dbc24c51b9d3e2f9e508e75cf8f99/raw/2a3fee4ee506a05cc4ac509f592f0c3af1ddfed4/infamous-mixed-mode-3.js"
script src="https://unpkg.com/tween.js@16.6.0/src/Tween.js"
i-scene experimental-webgl="true" id="scene" TODO-perspective="800" backgroundColor="0 0 0" backgroundOpacity="0" style="perspective: 800px" shadowmap-type="pcfsoft"
i-ambient-light color="#404040" intensity="1"
i-dom-plane id="bg" sizeMode="proportional proportional" size="1 1 0"
i-node id="button-container" position="0 0 6" size="600 31 0" align="0.5 0.5 0" mountPoint="0.5 0.5 0"
- for n in (0..4)
i-dom-plane sizeMode="literal proportional" size="100 1 0" align="#{n*0.25} 0 0" mountPoint="#{n*0.25} 0 0"
button button #{n+1}
i-point-light id="light" color="white" position="300 300 120" size="0 0 0" cast-shadow="true" intensity="1"
i-mesh has="sphere-geometry basic-material" size="10 10 10" color="white" receive-shadow="false" cast-shadow="false" style="pointer-events: none"
CSS(手写笔):
body, html
width 100%
height 100%
margin 0
padding 0
font-family sans-serif
i-node
text-align center
#bg
background #62B997
button
width 100%
height 100%
white-space nowrap
border-radius 0px
border 1px solid #534334
background lighten(#FB752C, 20%)
color darken(#534334, 10%)
outline none // remove those darn ugly browser-specific outlines
&:focus, &:hover
background #FB752C
color darken(#534334, 20%)
JavaScript:
infamous.html.useDefaultNames()
const Motor = infamous.core.Motor
light.threeObject3d.shadow.radius = 3
light.threeObject3d.distance = 20000
light.threeObject3d.shadow.bias = 0.00001
document.addEventListener('pointermove', e => {
e.preventDefault()
light.position.x = e.clientX
light.position.y = e.clientY
})
let downTween, upTween, pressedButton
// On mouse down animate the button downward
document.addEventListener('pointerdown', e => {
if ( is( e.target, 'button' ) ) {
pressedButton = e.target
if (upTween) {
upTween.stop()
upTween = null
}
downTween = new TWEEN.Tween(e.target.parentNode.position)
.to({z: -6}, 75)
.start()
.onComplete(() => downTween = null)
Motor.addRenderTask(time => {
if (!downTween) return false
downTween.update(time)
})
}
})
// On mouse up animate the button upward
document.addEventListener('pointerup', e => {
if ( pressedButton ) {
if (downTween) {
downTween.stop()
downTween = null
}
upTween = new TWEEN.Tween(pressedButton.parentNode.position)
.to({z: 0}, 75)
.start()
.onComplete(() => upTween = null)
Motor.addRenderTask(time => {
if (!upTween) return false
upTween.update(time)
})
}
})
// The following is a temporary hack because opacity isn't
// exposed through the HTML API yet. work-in-progress...
setTimeout(() => {
Array.from( document.querySelectorAll('i-dom-plane') ).forEach(n => {
n.threeObject3d.material.opacity = 0.3
})
scene._needsToBeRendered()
}, 0)
function is( el, selector ) {
if ( [].includes.call( document.querySelectorAll( selector ), el ) ) return true
return false
}
推荐答案
在有关pointermove
的MDN文档页面上,有以下一行:
On the MDN documentation page about pointermove
, there's this line:
当指针更改坐标且未通过浏览器触摸操作取消指针时,将触发pointermove事件.
源,重点是我的 >
source, emphasis mine
短时间后,(移动)浏览器将声明pointermove
事件用于自然"行为,例如平移页面.
After a short period of time, the (mobile) browser will claim the pointermove
event for "native" behavior like panning the page.
设计简单的解决方案是使用css属性 touch-action
,并在具有事件处理程序的容器上将其设置为none
.
The designed, simple solution is to use the css property touch-action
and set it to none
on the container that has the event handler.
这是添加到您的代码笔中的css属性: https://codepen.io/anon/pen/XVBMvL
Here's the css property added to your codepen: https://codepen.io/anon/pen/XVBMvL
或者在一个简化的示例中:
Or in a simplified example:
- 将浏览器设置为模拟触摸(在Chrome浏览器中,开发工具>传感器>触摸)
- 在左侧开始互动,点将跟随您的手指
- 在右侧开始互动,您会发现它会迅速失败,就像在提供的示例中一样
var dot = document.querySelector(".dot")
document.body.addEventListener("pointermove", function(ev) {
dot.style.transform = `translate3d(${ev.clientX}px, ${ev.clientY}px, 0)`;
}, false);
* { margin: 0; padding: 0 }
.wrapper {
display: flex;
height: 100vh;
}
.hasTouchAction,
.noTouchAction {
flex-grow: 1;
text-align: center;
background: #efefef;
}
.hasTouchAction {
touch-action: none;
}
.noTouchAction {
background: #ccc;
}
.dot {
width: 16px;
height: 16px;
border-radius: 50%;
background: red;
position: absolute;
top: -8px;
left: -8px;
}
<div class="wrapper">
<div class="hasTouchAction">
With <code>touch-action: none</code>
</div>
<div class="noTouchAction">
Without <code>touch-action</code>
</div>
</div>
<div class="dot"></div>
请确保您不会破坏重要的事情并不会损害可访问性.还花一些时间调查浏览器支持.这对我来说适用于Chrome中的触摸模拟事件,但可能不适用于所有浏览器...
Make sure you don't break important things and hurt accessibility. Also spend some time to investigate browser support. This worked for me with touch emulated events in Chrome, but might not work in every browser...
这篇关于"pointermove"事件无法与触摸配合使用.为什么不?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!