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

使用react-three/drei的OrbitControls时,GLB模型区域如何实现页面滚动?

解决OrbitControls抢占滚动捏合事件导致页面无法滚动的问题

针对你遇到的OrbitControls拦截滚动/捏合事件的问题,这里有几个实用的解决方案,覆盖不同的交互需求:


方案1:达到缩放边界时释放滚动事件

这个方案完全匹配你的需求——当模型缩放至最小/最大级别时,自动允许页面滚动,否则保持OrbitControls的缩放功能。

实现思路是监听滚轮事件,判断当前相机与模型目标点的距离是否触及minDistance或maxDistance,如果是,则取消OrbitControls对事件的拦截,让页面接收滚动信号。

import { useRef } from 'react';
import { OrbitControls } from '@react-three/drei';

export default function ModelViewer() {
  const controlsRef = useRef(null);
  const cameraRef = useRef(null);

  const handleWheel = (event) => {
    const controls = controlsRef.current;
    const camera = cameraRef.current;
    if (!controls || !camera) return;

    const currentDistance = camera.position.distanceTo(controls.target);
    const hitMinZoom = currentDistance <= controls.minDistance;
    const hitMaxZoom = currentDistance >= controls.maxDistance;

    // 向下滚动时已到最小缩放,或向上滚动时已到最大缩放,允许页面滚动
    if ((hitMinZoom && event.deltaY > 0) || (hitMaxZoom && event.deltaY < 0)) {
      event.stopPropagation = () => {};
      event.preventDefault = () => {};
    }
  };

  return (
    <group>
      {/* 替换为你的GLB模型组件 */}
      {/* <GLBModel /> */}
      <OrbitControls
        ref={controlsRef}
        minDistance={5} // 根据你的模型尺寸调整
        maxDistance={50} // 根据你的模型尺寸调整
        enableZoom={true}
        onWheel={handleWheel}
      />
      <perspectiveCamera ref={cameraRef} />
    </group>
  );
}

方案2:仅在交互时启用缩放

如果不需要严格的边界控制,这个方案更简单——只有当用户点击/触摸模型区域时,才让OrbitControls接管缩放事件,平时滚动直接作用于页面。

import { useState } from 'react';
import { OrbitControls } from '@react-three/drei';

export default function ModelViewer() {
  const [isInteracting, setIsInteracting] = useState(false);

  return (
    <group
      onPointerDown={() => setIsInteracting(true)}
      onPointerUp={() => setIsInteracting(false)}
      onPointerLeave={() => setIsInteracting(false)}
    >
      {/* 替换为你的GLB模型组件 */}
      {/* <GLBModel /> */}
      <OrbitControls
        enableZoom={isInteracting}
        enablePan={isInteracting} // 可选:同时禁用平移,避免误触
      />
    </group>
  );
}

方案3:重写OrbitControls的滚轮处理逻辑

如果需要更底层的控制,可以直接修改OrbitControls的内置滚轮事件处理函数,在达到边界时跳过缩放逻辑。

import { useRef, useEffect } from 'react';
import { OrbitControls } from '@react-three/drei';

export default function ModelViewer() {
  const controlsRef = useRef(null);

  useEffect(() => {
    const controls = controlsRef.current;
    if (!controls) return;

    // 保存原始的滚轮处理函数
    const originalWheelHandler = controls.handleWheel;

    // 重写滚轮处理逻辑
    controls.handleWheel = function (event) {
      const currentDistance = this.camera.position.distanceTo(this.target);
      const hitMinZoom = currentDistance <= this.minDistance;
      const hitMaxZoom = currentDistance >= this.maxDistance;

      // 触及边界时,不执行缩放,直接放行事件
      if ((hitMinZoom && event.deltaY > 0) || (hitMaxZoom && event.deltaY < 0)) {
        return;
      }

      // 否则执行原始缩放逻辑
      originalWheelHandler.call(this, event);
    };

    // 组件卸载时恢复原始逻辑
    return () => {
      if (controls) controls.handleWheel = originalWheelHandler;
    };
  }, []);

  return (
    <group>
      {/* 替换为你的GLB模型组件 */}
      {/* <GLBModel /> */}
      <OrbitControls
        ref={controlsRef}
        minDistance={5}
        maxDistance={50}
        enableZoom={true}
      />
    </group>
  );
}

内容的提问来源于stack exchange,提问作者Poonam Kaushal

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.21 15:53:27