pointermove事件触摸设备失效修复及下拉刷新禁用方案咨询
修复触摸拖动光球问题 + 禁用下拉刷新方案
Hey, let's fix those touch interaction issues you're seeing! Here's what's going on and how to resolve it:
问题根源
On touch devices, browsers prioritize default gestures like scrolling or pull-to-refresh over custom pointer events. When you start dragging the light, the browser takes over and stops sending pointermove events to your code. Also, we weren't properly handling the full touch interaction lifecycle (like pointercancel which fires if the browser interrupts your touch session).
解决方案步骤
1. 让光球持续跟随触摸拖动
- Track when we're actively dragging the light (only when clicking/tapping outside the buttons)
- Block browser default behaviors during drag to keep
pointermovefiring consistently - Clean up the drag state when the user lifts their finger or the browser interrupts the touch
2. Disable pull-to-refresh
- We'll block the default touchmove behavior only when we're dragging the light, so button clicks still work normally
完整修改后的代码
HTML (Slim)
/! 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 (Stylus)
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 // Track if we're actively dragging the light let isDraggingLight = false let pressedButton, downTween, upTween // Handle start of interaction document.addEventListener('pointerdown', e => { // Start dragging if we're not clicking a button if (!is(e.target, 'button') && !e.target.closest('button')) { isDraggingLight = true e.preventDefault() // Block browser defaults to keep pointermove firing } // Original button press logic if (is(e.target, 'button')) { pressedButton = e.target 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) }) } }) // Update light position only when dragging document.addEventListener('pointermove', e => { if (isDraggingLight) { e.preventDefault() light.position.x = e.clientX light.position.y = e.clientY } }) // End dragging when user lifts finger or browser interrupts document.addEventListener('pointerup', () => { isDraggingLight = false }) document.addEventListener('pointercancel', () => { isDraggingLight = false }) // Original button release logic document.addEventListener('pointerup', e => { if (!pressedButton) return 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) }) pressedButton = null }) // Disable pull-to-refresh by blocking touchmove during drag document.addEventListener('touchmove', e => { if (isDraggingLight) { e.preventDefault() } }, { passive: false }) // Required to allow preventDefault on touchmove // Temporary opacity fix (original code) setTimeout(() => { Array.from(document.querySelectorAll('i-dom-plane')).forEach(n => { n.threeObject3d.material.opacity = 0.3 }) scene._needsToBeRendered() }, 0) // Helper function (original code) function is(el, selector) { return [].includes.call(document.querySelectorAll(selector), el) }
关键修改说明
- Drag State Tracking: Added
isDraggingLightto only processpointermovewhen we're actually dragging the light (not clicking buttons). - Prevent Default Behaviors: Called
e.preventDefault()inpointerdown(drag start) andtouchmove(during drag) to stop the browser from hijacking the event. We setpassive: falseon thetouchmovelistener because browsers default to passive for performance, which blockspreventDefault. - Handle
pointercancel: This event fires if the browser interrupts your touch (like if you switch apps or use a system gesture), so we reset the drag state here to avoid broken interactions. - Cleaned Up Button Logic: Used optional chaining (
?.) to make the tween cleanup cleaner, and consolidated variable declarations for better scoping.
内容的提问来源于stack exchange,提问作者trusktr
相关产品推荐
相关产品推荐

