如何在HTML元素上模拟touchmove事件以触发自定义滚动?
Hey there, I’ve run into similar issues with simulating touch events for custom scroll containers when dealing with heavy framework-based sites—let me walk you through exactly how to make this work.
The key thing to remember is that custom scroll logic almost always relies on the full sequence of touch events: touchstart (to initialize the scroll state), repeated touchmove (to calculate scroll displacement), and touchend (to wrap up any inertia or cleanup). Skipping any part of this chain might make the custom scroll ignore your simulation.
Here's a step-by-step implementation:
First, we’ll create a helper function to generate valid touch events, then a function to simulate the full swipe sequence.
// Grab your target custom scroll div (replace with your selector) const targetScrollDiv = document.querySelector('#your-custom-scroll-div'); // Helper to create a properly-formatted TouchEvent function createTouchEvent(eventType, touchPoints, targetElement) { return new TouchEvent(eventType, { bubbles: true, cancelable: true, view: window, touches: touchPoints, targetTouches: touchPoints, changedTouches: touchPoints }); } // Main function to simulate a touch scroll function simulateTouchSwipe(element, startY, endY, stepSize = 10) { // Create a unique touch point (identifier avoids conflicts with real touches) const touch = new Touch({ identifier: Date.now(), target: element, clientX: element.getBoundingClientRect().left + 50, // X position inside the div clientY: startY, screenX: window.screenX + 50, screenY: startY, pageX: window.pageXOffset + 50, pageY: startY }); // 1. Trigger touchstart to tell the scroll container we're starting a swipe element.dispatchEvent(createTouchEvent('touchstart', [touch], element)); // 2. Simulate incremental touchmove events to mimic a smooth swipe let currentY = startY; const swipeInterval = setInterval(() => { // Update the touch point's Y position touch.clientY = currentY; touch.screenY = currentY; touch.pageY = currentY; // Fire the touchmove event element.dispatchEvent(createTouchEvent('touchmove', [touch], element)); // Adjust position towards the end point if (startY > endY) { currentY -= stepSize; if (currentY <= endY) clearInterval(swipeInterval); } else { currentY += stepSize; if (currentY >= endY) clearInterval(swipeInterval); } }, 16); // ~60fps to match real user swipe smoothness // 3. Trigger touchend once the swipe is complete setTimeout(() => { clearInterval(swipeInterval); element.dispatchEvent(createTouchEvent('touchend', [touch], element)); }, Math.abs(startY - endY) / stepSize * 16 + 50); } // Example usage: Swipe from Y=100 to Y=300 (downward swipe, makes the div scroll up) simulateTouchSwipe(targetScrollDiv, 100, 300);
Key details to note:
- Full event chain: Don’t skip
touchstartortouchend—most custom scroll implementations initialize state ontouchstart(like capturing the initial scroll position) and finalize ontouchend(like applying inertia). - Unique touch identifier: Using
Date.now()ensures your simulated touch doesn’t collide with real user touches. - Smoothness adjustment: Tweak
stepSize(pixels per frame) and thesetIntervaldelay to make the swipe feel more natural. Smaller steps = smoother swipe. - Framework compatibility: If you’re using React/Vue/Svelte, make sure to run this code after the element is mounted to the DOM (e.g., in
useEffectormountedhooks).
If your custom scroll relies on specific event properties (like deltaY), you might need to add those to the TouchEvent options, but most implementations calculate scroll displacement from the changedTouches coordinates—this code should cover that case.
内容的提问来源于stack exchange,提问作者Jake C

