本文详细讲解如何在 vue 3(javascript 版本)项目中正确集成 three.js,完成基础 3d 场景渲染,涵盖 dom 挂载时机、渲染循环管理、响应式容器适配等关键实践。
本文详细讲解如何在 vue 3(javascript 版本)项目中正确集成 three.js,完成基础 3d 场景渲染,涵盖 dom 挂载时机、渲染循环管理、响应式容器适配等关键实践。
在 Vue 3 的组合式 API(Composition API)中集成 Three.js 时,核心挑战在于:确保 WebGL 渲染器挂载到真实 DOM 节点后再启动动画循环,避免因节点未就绪导致 appendChild 失败或渲染空白。以下是一个生产就绪、结构清晰的实现方案。
✅ 正确做法:使用 ref + onMounted 管理生命周期
首先,通过 ref 创建一个 DOM 容器引用,并在 onMounted 钩子中执行 Three.js 初始化与动画启动——这是最安全、最符合 Vue 3 响应式逻辑的方式:
DMap GL地图JSAPI(dmapgl)开发指南。用于编写、审查、调试 DMap 地图 API 代码,涵盖地图初始化、覆盖物渲染、图层管理、事件处理、控件交互等任务。当用户提及 dmap、dmapgl、jsapi‑gl 或相关地图开发需求时自动触发。
<!-- App.vue -->
<script setup>
import { ref, onMounted, onUnmounted } from 'vue';
import * as THREE from 'three';
// 创建 DOM 容器引用
const target = ref(null);
// 初始化 Three.js 核心对象
const scene = new THREE.Scene();
const camera = new THREE.PerspectiveCamera(
75, // FOV
window.innerWidth / window.innerHeight, // 宽高比
0.1, // 近裁剪面
1000 // 远裁剪面
);
camera.position.z = 5;
const renderer = new THREE.WebGLRenderer({ antialias: true });
renderer.setSize(500, 500); // 初始尺寸(可后续动态调整)
renderer.setPixelRatio(window.devicePixelRatio); // 提升高清屏显示质量
// 创建绿色立方体
const geometry = new THREE.BoxGeometry(1, 1, 1);
const material = new THREE.MeshBasicMaterial({ color: 0x00ff00 });
const cube = new THREE.Mesh(geometry, material);
scene.add(cube);
// 动画循环函数(闭包内保持对 scene/camera/renderer/cube 的引用)
let animationId = null;
function animate() {
animationId = requestAnimationFrame(animate);
cube.rotation.x += 0.01;
cube.rotation.y += 0.01;
renderer.render(scene, camera);
}
// 组件挂载后:将渲染器 canvas 插入 DOM,并启动动画
onMounted(() => {
if (target.value) {
target.value.appendChild(renderer.domElement);
animate();
}
});
// 【重要】组件卸载前清理资源,防止内存泄漏
onUnmounted(() => {
if (animationId) {
cancelAnimationFrame(animationId);
}
if (renderer.domElement && renderer.domElement.parentNode) {
renderer.domElement.parentNode.removeChild(renderer.domElement);
}
renderer.dispose(); // 释放 WebGL 资源
});
</script>
<template>
<div ref="target" class="three-container"></div>
</template>
<style scoped>
.three-container {
width: 100%;
height: 500px;
margin: 0 auto;
background: #000;
}
</style>⚠️ 关键注意事项
- 不要在 <script setup> 顶层直接操作 document.body:Vue 3 组件可能被复用或延迟挂载,document.body.appendChild() 会污染全局、破坏组件封装性,且在 SSR 或微前端场景下完全失效。
- 尺寸适配建议:示例中使用固定 500×500 尺寸便于演示;实际项目中可监听 window.resize 并调用 renderer.setSize() 同步更新,同时重设 camera.aspect 和 camera.updateProjectionMatrix()。
- 性能与资源管理:务必在 onUnmounted 中取消 requestAnimationFrame、移除 canvas 节点并调用 renderer.dispose() —— 否则组件反复创建/销毁将导致 GPU 内存持续增长。
- TypeScript 友好提示:虽然本例使用 JavaScript,但若未来迁移至 TS,建议为 target 添加类型 HTMLElement | null,并使用非空断言(如 target.value!)配合严格检查。
✅ 总结
该实现遵循 Vue 3 最佳实践:
? 利用 ref 精准控制 DOM 插入点;
? 借助 onMounted/onUnmounted 确保生命周期同步;
? 封装完整资源清理链路,保障应用长期稳定性;
? 代码模块化、无副作用、可复用性强。
掌握此模式后,你可无缝扩展功能——如添加光照、纹理、轨道控制器(OrbitControls)、GLTF 模型加载等,真正开启 Vue + Three.js 的 3D 应用开发之旅。

















