使用 Three.js 与 Iframe 交互后,网页在移动设备上崩溃

问题描述 投票:0回答:1

我有一个包含 Iframe 的模态,它利用 Three.js 加载 3d 门。

Iframe 在桌面上运行良好,但是,当我们在移动设备上与它交互时,当我们关闭模式时,它会崩溃或重新加载页面。在 safari 上,页面会重新加载,但在第二次重新加载时,页面会崩溃

页面加载 Iframe

<iframe loading="lazy" id="door-viewer" src="<?= "{$site_url}/3d-spinner.php?sku={$unique_skus[0]}"; ?>" sandbox></iframe>

生成iframe的文件

<?php 
   $product_sku = isset($_GET['sku']) ? strtoupper($_GET['sku']) : null;

    $proto = $_SERVER['HTTP_X_FORWARDED_PROTO'];
    $name = $_SERVER['SERVER_NAME'];

    $site_url = "{$proto}://{$name}";
?>
<?php
    header("Content-Security-Policy: frame-ancestors 'self' ".file_get_contents(getcwd()."/3d-spinner-assets/allowed-domains.txt").";");
?>
<html>
    <head>
        <!-- Three JS CDN Scripts -->
        <script async src="https://unpkg.com/[email protected]/dist/es-module-shims.js"></script>
        <script type="importmap">
        {
            "imports": {
            "three": "https://unpkg.com/[email protected]/build/three.module.js",
            "three/addons/": "https://unpkg.com/[email protected]/examples/jsm/"
            }
        }
        </script>
        <!-- IFRAME STYLES -->
        <style>
            body {
                margin: 0;
                box-sizing: border-box;
            }
            canvas {
                object-fit: cover;
                width: 100% !important;
                height: 100% !important;
                aspect-ratio: 1;
                background-image: radial-gradient(at 50% 50%, rgb(245, 245, 245) 20%, rgb(206, 206, 206) 90%);
            }

            .lpd-360-image-icon {
                position: absolute;
                top: 2rem;
                left: 2rem;
            }

            #door-viewer {
                position: relative;
            }

            noscript {
                display: flex;
                align-items: center;
                justify-self: center;
                font-size: 2rem;
                height: 100vw;
                width: 100vw;
            }
        </style>
    </head>
    <body>
        <noscript>
            Please enable JavaScript and reload your browser
        </noscript>
        <?php if($product_sku) : ?>
            <div id="door-viewer">
                <!-- Canvas is injected via Three.js -->
            </div>
        <?php else : ?>
            <div>
                <p>Product not found, check your sku</p>
            </div>
        <?php endif; ?>
        <script type="module">
            const sku = "<?= preg_replace('/[^-a-zA-Z0-9_]/', '', $product_sku ); ?>"
            const site_url = "<?= $site_url; ?>"

            import initSpinner from "./3d-spinner-assets/assets/scripts/main.js"

            initSpinner(sku, site_url);
        </script>
    </body>
</html>

主.js文件

import * as THREE from "three";
import { GLTFLoader } from "three/addons/loaders/GLTFLoader.js";
import { OrbitControls } from "three/addons/controls/OrbitControls.js";

function initSpinner(sku, site_url) {
      const doorAssetPath = `${site_url}/3d-spinner-assets/door/${sku}/model.gltf"`;
      const doorViewerCanvas = document.getElementById("door-viewer");

      // Scene
      const scene = new THREE.Scene();

      // Camera
      const camera = new THREE.PerspectiveCamera(75, 500 / 500, 0.1, 800);
      camera.position.z = 10;
      camera.position.y = 0;
      camera.position.x = 0;

      // Renderer
      const renderer = new THREE.WebGLRenderer({
        antialias: true,
        devicePixelRatio: 1,
        alpha: true,
      });
      renderer.setSize(1200, 1200); // Set Scene Size
      renderer.shadowMap.enabled = true;
      renderer.setClearColor(0xffffff, 0); // Make scene transparent
      renderer.setPixelRatio(window.devicePixelRatio); // Set Pixel Ratio in line with device

      // Scene Lighting
      const ambientLight = new THREE.AmbientLight(0x404040, 90);
      scene.add(ambientLight);

      // Controls
      const controls = new OrbitControls(camera, renderer.domElement);
      controls.enableDamping = true; // Add damping for smoother motion
      controls.dampingFactor = 0.05; // Adjust the damping factor
      controls.rotateSpeed = 0.5; // Adjust rotation speed
      controls.zoomSpeed = 1.2; // Adjust zoom speed

      // Load Door
      const loader = new GLTFLoader();
      loader.load(doorAssetPath, (gltfScene) => {
        const loadedDoor = gltfScene.scene;

        // Traverse the loadedDoor to set transparency for the windows
        const windowMaterials = []; // Add the window materials to this array

        // Inside the load callback function
        loadedDoor.traverse((child) => {
          if (
            (child.isMesh && child.name === "glass") ||
            child.name === "Glass"
          ) {
            const windowMaterial = child.material;
            windowMaterial.transparent = true;
            windowMaterial.opacity = 0; // Adjust opacity value
            windowMaterials.push(windowMaterial);
          }
        });

        const scaleFactor = 0.003; // Adjust this value as needed
        loadedDoor.scale.set(scaleFactor, scaleFactor, scaleFactor); // Adjust door's scale 
        loadedDoor.position.setY(-3); // Offset door's position
        scene.add(loadedDoor); // Add the door to the scene
      });

      doorViewerCanvas.appendChild(renderer.domElement); // Mount canvas to the DOM

      function animate() {
        requestAnimationFrame(animate);
        controls.update(); // Update the controls
        renderer.render(scene, camera);
      }

      animate();
}

export default initSpinner;

我寻找过内存泄漏,但找不到任何东西

javascript iframe mobile three.js
1个回答
0
投票

我找到了解决方案,画布在移动设备上加载时宽度约为 3000px。我必须更新 html 以包含

<meta name="viewport" content="width=device-width, initial-scale=1.0">

并更新 main.js 文件以获取窗口的宽度和高度


  // Camera
  const camera = new THREE.PerspectiveCamera(
    75,
    window.innerWidth / window.innerHeight,
    0.1,
    800
  );
  camera.position.z = 5;
  camera.position.y = 0;
  camera.position.x = 0;

  // Renderer
  const renderer = new THREE.WebGLRenderer({
    antialias: true,
    devicePixelRatio: window.devicePixelRatio,
    alpha: true,
  });
© www.soinside.com 2019 - 2024. All rights reserved.