使用 Three.js 与 CSS3DRenderer 在 Vue3 中加载网页为 3D 模型

在 Web 开发中,Three.js 是一个非常强大的 3D 渲染库,而 CSS3DRenderer 则可以将 HTML 元素(如 iframe)渲染到 3D 场景中,这使得我们可以将普通网页嵌入并展示在三维空间中,赋予 Web 页面更酷的交互形式。

本文将带你一步一步在 Vue3 项目中使用 Three.js + CSS3DRenderer 实现一个可交互、可缩放旋转的 3D 网页嵌入效果。

项目介绍

我们的目标是:

  • 使用 Three.js 创建一个三维场景;
  • 使用 CSS3DRenderer 将网页(iframe)加载为 3D 对象;
  • 使用 OrbitControls 实现鼠标交互控制;
  • 所有内容封装在 Vue3 <script setup> 中运行。

核心技术栈

  • Vue 3
  • Three.js
  • three/examples/jsm/renderers/CSS3DRenderer.js
  • three/examples/jsm/controls/OrbitControls.js

代码详解

1. HTML 模板结构

html 复制代码
<template>
  <div class="box" ref="box"></div>
</template>

我们在页面中只保留一个容器 box,所有 3D 内容都将渲染到这个容器中。

2. 初始化场景核心逻辑

下面是初始化场景的完整逻辑:

javascript 复制代码
const initScene = () => new THREE.Scene();
javascript 复制代码
const initCamera = (boxElement) => {
  const camera = new THREE.PerspectiveCamera(75, boxElement.clientWidth / boxElement.clientHeight, 1, 6000);
  camera.position.z = 3000;
  camera.lookAt(0, 0, 0);
  return camera;
};
javascript 复制代码
const initRenderer = (boxElement) => {
  const renderer = new THREE.WebGLRenderer({ antialias: true });
  renderer.setClearColor(0xffffff); // 背景设置为白色
  renderer.setSize(boxElement.clientWidth, boxElement.clientHeight);
  boxElement.appendChild(renderer.domElement);
  return renderer;
};

3. CSS3D 渲染器初始化

CSS3DRenderer 会创建一个可以渲染 DOM 元素的 3D 渲染器。通过它我们可以将 iframe 包装成 DOM 元素再变成 CSS3DObject 加入到场景中。

javascript 复制代码
const initLabelRenderer = (boxElement) => {
  const labelRenderer = new CSS3DRenderer();
  labelRenderer.setSize(window.innerWidth, window.innerHeight);
  labelRenderer.domElement.style.position = 'absolute';
  labelRenderer.domElement.style.top = '0';
  boxElement.appendChild(labelRenderer.domElement);
  return labelRenderer;
};

4. 嵌入网页模型

javascript 复制代码
const initModel = (scene, w, h, url) => {
  const domEle = document.createElement('div');
  domEle.innerHTML = `
    <div style="width:${w}px; height:${h}px;">
      <iframe src="${url}" width="${w}" height="${h}" frameborder="0"></iframe>
    </div>
  `;
  const domEleObj = new CSS3DObject(domEle);
  domEleObj.position.set(0, 0, 0);
  scene.add(domEleObj);
};

你可以把任意网页以 iframe 的形式加载进来,并作为 3D 模型对象在场景中展示。


5. 渲染逻辑与交互控制

创建完所有元素后,我们通过 OrbitControls 实现摄像机的缩放/旋转/平移交互:

javascript 复制代码
const controls = new OrbitControls(camera, labelRenderer.domElement);
controls.update();

然后使用渲染函数刷新场景:

javascript 复制代码
const render = (renderer, scene, camera, labelRenderer) => {
  renderer.render(scene, camera);
  labelRenderer.render(scene, camera);
};

const animate = () => {
  requestAnimationFrame(animate);
  render(renderer, scene, camera, labelRenderer);
};

最后在 onMounted 中初始化所有内容:

javascript 复制代码
onMounted(() => {
  if (!box.value) return;

  const scene = initScene();
  const labelRenderer = initLabelRenderer(box.value);
  const camera = initCamera(box.value);
  const renderer = initRenderer(box.value);

  const controls = new OrbitControls(camera, labelRenderer.domElement);
  controls.update();

  initModel(scene, 1920, 1080, 'https://www.baidu.com/');

  animate();
});

完整代码

javascript 复制代码
<template>
  <div class="box" ref="box"></div>
</template>

<script setup>
import { ref, onMounted } from 'vue';
import * as THREE from 'three';
import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls.js'; // 引入 OrbitControls
import { CSS3DRenderer, CSS3DObject } from 'three/examples/jsm/renderers/CSS3DRenderer.js';

const box = ref(null);

/**
 * 初始化场景
 */
const initScene = () => {
  const scene = new THREE.Scene();
  return scene;
};

/**
 * 初始化相机
 * @param {*} boxElement 盒子元素
 */
const initCamera = boxElement => {
  const camera = new THREE.PerspectiveCamera(
    75,
    boxElement.clientWidth / boxElement.clientHeight,
    1,
    6000
  );
  camera.lookAt(0, 0, 0);
  camera.position.z = 3000;
  // camera.position.x = 20;
  // camera.position.y = 20;
  return camera;
};

/**
 * 初始化渲染器
 * @param {*} boxElement 盒子元素
 */
const initRenderer = boxElement => {
  const renderer = new THREE.WebGLRenderer({ antialias: true }); // 设置抗锯齿
  renderer.setClearColor(0xffffff); // 将背景颜色设置为白色
  renderer.setSize(boxElement.clientWidth, boxElement.clientHeight);
  boxElement.appendChild(renderer.domElement);
  return renderer;
};

/**
 * 构建CSS 3D渲染器
 * @param {*} boxElement 盒子元素
 */
const initLabelRenderer = boxElement => {
  const labelRenderer = new CSS3DRenderer();
  labelRenderer.setSize(window.innerWidth, window.innerHeight);
  labelRenderer.domElement.style.position = 'absolute';
  labelRenderer.domElement.style.top = 0;
  boxElement.appendChild(labelRenderer.domElement);
  return labelRenderer;
};

/**
 * 初始化模型
 * @param {*} s 场景 必传
 * @param {*} w 宽
 * @param {*} h 高
 * @param {*} url iframe链接地址
 */
const initModel = (s, w, h, url) => {
  const domEle = document.createElement('div');
  const html = `
  <div style="width:${w}px; height:${h}px;">
    <iframe src="${url}" width="${w}" height="${h}" frameborder=0></iframe>
  </div>
  `;
  domEle.innerHTML = html;
  const domEleObj = new CSS3DObject(domEle);
  domEleObj.position.set(0, 0, 0);
  s.add(domEleObj);
};

// 渲染场景于css3D渲染器
const render = (renderer, scene, camera, labelRenderer) => {
  renderer.render(scene, camera);
  labelRenderer.render(scene, camera);
};

onMounted(() => {
  // 确保 box 元素存在
  if (!box.value) return;

  // 初始化场景
  const scene = initScene();

  // 初始化CSS 3D渲染器
  const labelRenderer = initLabelRenderer(box.value);

  // 初始化相机
  const camera = initCamera(box.value);

  // 初始化渲染器
  const renderer = initRenderer(box.value);

  // 创建 OrbitControls 控制器
  const controls = new OrbitControls(camera, labelRenderer.domElement);
  controls.update(); // 更新控制器以确保有效初始状态

  // 初始化模型
  initModel(scene, 1920, 1080, 'https://www.baidu.com/');

  // 定义动画函数
  const animate = () => {
    requestAnimationFrame(animate); // 请求下一帧动画
    render(renderer, scene, camera, labelRenderer); // 渲染场景
  };

  animate(); // 开始动画循环
});
</script>

<style scoped>
.box {
  width: 100vw;
  height: 100vh;
}

.domBox {
  background-color: aqua;
}
</style>

最终效果

你可以通过鼠标拖动、缩放、旋转视角,从三维空间中观察你加载的网页内容。这种方式非常适用于以下场景:

  • 可视化多个网页窗口或大屏展示;
  • 将网页内容融入 3D 虚拟世界;
  • 创建沉浸式交互体验。

小结

通过结合 Vue3 与 Three.js 的 CSS3D 渲染器,我们实现了一个非常炫酷的 3D 网页展示方式。你可以进一步扩展此项目,支持拖拽网页、动态加载内容、添加多个 iframe 组合成 3D 空间 UI 等。


拓展方向

  • 动态切换 iframe 页面;
  • 支持多 iframe 多视角布局;
  • 支持鼠标拖动模型位置;
  • 与 WebXR 或 WebGPU 结合实现更高级别的互动。
相关推荐
前端大卫3 小时前
Vue3 + Element-Plus 自定义虚拟表格滚动实现方案【附源码】
前端
却尘3 小时前
Next.js 请求最佳实践 - vercel 2026一月发布指南
前端·react.js·next.js
ccnocare3 小时前
浅浅看一下设计模式
前端
Lee川3 小时前
🎬 从标签到屏幕:揭秘现代网页构建与适配之道
前端·面试
Ticnix3 小时前
ECharts初始化、销毁、resize 适配组件封装(含完整封装代码)
前端·echarts
纯爱掌门人3 小时前
终焉轮回里,藏着 AI 与人类的答案
前端·人工智能·aigc
twl4 小时前
OpenClaw 深度技术解析
前端
崔庆才丨静觅4 小时前
比官方便宜一半以上!Grok API 申请及使用
前端
星光不问赶路人4 小时前
vue3使用jsx语法详解
前端·vue.js
天蓝色的鱼鱼4 小时前
shadcn/ui,给你一个真正可控的UI组件库
前端