You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.26 19:30:35