React应用中OrbitControls导致触控设备无法滚动的问题求助
React中OrbitControls导致触控设备无法滚动页面的解决方案
问题详情
在React应用中使用@react-three/drei的OrbitControls组件时,触控设备无法通过触摸手势滚动页面。尝试设置enabled=false未解决问题。
相关代码
import { OrbitControls, PerspectiveCamera, View } from "@react-three/drei"; import Lights from "./Lights"; import { Suspense } from "react"; import IPhone from "./IPhone"; import * as THREE from "three"; import { Loader } from "./Loader"; export const ModelView = ({ index, groupRef, gsapType, controlRef, setRotationState, item, size, }) => { return ( <View index={index} id={gsapType} className={` w-full h-full absolute ${ index == 2 ? "right-[-100%]" : "" } `} > {/* Ambient Light ddd*/} <ambientLight intensity={0.5} /> <PerspectiveCamera makeDefault position={[0, 0, 4]} /> <Lights /> <OrbitControls makeDefault ref={controlRef} enableZoom={false} enablePan={false} rotateSpeed={0.4} target={new THREE.Vector3(0, 0, 0)} onEnd={(e) => { setRotationState(controlRef.current.getAzimuthalAngle()); }} /> <group ref={groupRef} name={`${index === 1} ? "small" : "large"`} position={[0, 0, 0]} > <Suspense fallback={<Loader />}> <IPhone scale={index === 1 ? [15, 15, 15] : [17, 17, 17]} item={item} size={size} /> </Suspense> </group> </View> ); };
可行解决方案
方案1:修改容器触摸行为(推荐)
OrbitControls默认会将其绑定的DOM元素的touchAction设为none,这会阻止页面原生滚动。我们可以在组件挂载后手动调整该属性,允许页面垂直滚动的同时保留OrbitControls的旋转功能:
import { useEffect } from 'react'; export const ModelView = ({ index, groupRef, gsapType, controlRef, setRotationState, item, size, }) => { useEffect(() => { if (controlRef.current) { // 允许页面垂直滚动,双指仍可旋转模型 controlRef.current.domElement.style.touchAction = 'pan-y'; // 若需要水平滚动,可设为 'pan-x pan-y' } }, [controlRef]); // 原组件return内容不变 };
方案2:过滤触摸事件,区分单指/双指操作
通过监听触摸事件,仅让双指操作触发OrbitControls,单指操作交给页面滚动:
<OrbitControls makeDefault ref={controlRef} enableZoom={false} enablePan={false} rotateSpeed={0.4} target={new THREE.Vector3(0, 0, 0)} onEnd={(e) => { setRotationState(controlRef.current.getAzimuthalAngle()); }} // 自定义触摸事件处理 onTouchStart={(event) => { // 只有双指触摸时,让OrbitControls处理事件 if (event.touches.length !== 2) { event.stopPropagation(); } }} />
方案3:动态启用/禁用OrbitControls
根据触摸点数动态切换OrbitControls的启用状态,单指滚动时禁用控件,双指旋转时启用:
import { useEffect } from 'react'; export const ModelView = ({ index, groupRef, gsapType, controlRef, setRotationState, item, size, }) => { useEffect(() => { const handleTouchStart = (e) => { if (controlRef.current) { controlRef.current.enabled = e.touches.length === 2; } }; const handleTouchEnd = () => { if (controlRef.current) { controlRef.current.enabled = true; } }; window.addEventListener('touchstart', handleTouchStart); window.addEventListener('touchend', handleTouchEnd); return () => { window.removeEventListener('touchstart', handleTouchStart); window.removeEventListener('touchend', handleTouchEnd); }; }, [controlRef]); // 原组件return内容不变 };
内容的提问来源于stack exchange,提问作者Juan Camilo Echeverri Salazar
相关产品推荐
相关产品推荐

