当前位置: 首页 > news >正文

Vue 3 中集成 Three.js 场景的完整实践指南

本文详解如何在 vue 3(javascript 版本)项目中正确集成 three.js 基础场景,涵盖 dom 挂载、生命周期协调、渲染循环管理及常见陷阱规避。 本文详解如何在 vue 3(javascript 版本)项目中正确集成 three.js 基础场景,涵盖 dom 挂载、生命周期协调、渲染循环管理及常见陷阱规避。在 Vue 3 的响应式架构下直接嵌入 Three.js 渲染逻辑,需特别注意 DOM 元素可用性、渲染器生命周期与 Vue 组件生命周期的协同。原生 Three.js 示例依赖 document.body.appendChild(),但在 Vue 单文件组件(SFC)中,必须通过 ref 获取真实 DOM 节点,并在 onMounted 钩子中安全挂载渲染器——这是避免 Cannot read property 'appendChild' of null 等错误的关键。以下是一个可直接运行的 App.vue 完整实现(使用 JavaScript,非 TypeScript):<script setup>import { ref, onMounted, onUnmounted } from 'vue';import * as THREE from 'three';// 创建 DOM 引用容器const target = ref();// 初始化 Three.js 核心对象const scene = new THREE.Scene();const camera = new THREE.PerspectiveCamera( 75, window.innerWidth / window.innerHeight, 0.1, 1000);const renderer = new THREE.WebGLRenderer({ antialias: true });renderer.setSize(500, 500); // 推荐显式设置尺寸,避免默认拉伸renderer.setPixelRatio(window.devicePixelRatio); // 提升高 DPI 屏幕显示质量// 创建绿色立方体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);camera.position.z = 5;// 动画循环函数(闭包内维持引用,避免重复创建)let animationId = null;function animate() { animationId = requestAnimationFrame(animate); cube.rotation.x += 0.01; cube.rotation.y += 0.01; renderer.render(scene, camera);}// 组件挂载后:挂载渲染器 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: 500px; height: 500px; margin: 2rem auto; border: 1px solid #eee;}</style>? 关键要点说明: ref + onMounted 是黄金组合:确保 renderer.domElement 只在真实 DOM 节点就绪后才插入; 显式 setSize() 优于 renderer.setSize(window.innerWidth, ...):避免因响应式容器尺寸变化导致渲染异常,推荐结合 CSS 控制容器宽高,Three.js 渲染器按需适配; 务必调用 renderer.dispose() 和 cancelAnimationFrame:Vue 组件可能被复用或销毁,未清理的动画帧和 WebGL 上下文将引发内存泄漏; 添加 antialias: true 和 setPixelRatio:显著提升视觉质量,尤其在 Retina 屏幕上; 避免在 setup() 顶层执行渲染逻辑:Three.js 对象(如 scene, camera)可定义在顶层,但 DOM 操作与动画启动必须延迟至 onMounted。? 进阶提示:如需响应窗口缩放,可监听 window.resize 事件并更新 camera.aspect 与 renderer.setSize(),但需注意防抖以避免高频重绘。 Zeemo AI 一款专业的视频字幕制作和视频处理工具

http://www.jsqmd.com/news/659091/

相关文章:

  • ArcGIS字段值精准拆解:VB与Python脚本的实战应用
  • 极域电子教室优化工具:3步实现课堂多任务自由学习
  • 5分钟掌握Umi-OCR:免费高效的离线文字识别终极指南
  • 2026年比较好的动力刀塔数控机床/数控车铣复合机床/斜导轨数控机床/玉环斜导轨数控机床厂家精选合集 - 行业平台推荐
  • RaiseCOM(瑞斯康达)交换机实战配置指南:从基础到高级
  • 别再只盯着CMOS了!聊聊LVDS在FPGA高速接口设计中的那些‘坑’与实战技巧
  • 从元器件到高速PCB:我的硬件工程师书单升级之路(附避坑指南)
  • 手把手教你用树莓派4B搭建OpenBMC开发环境(Ubuntu 20.04版,含编译加速技巧)
  • 阅读APP书源终极指南:解锁全网小说资源的完整解决方案
  • 3分钟快速安装Figma中文界面插件:设计师必备的免费汉化工具
  • 【智能代码生成个性化适配策略】:20年架构师亲授3层动态适配模型,解决92%的IDE场景错配问题
  • Python+Selenium实战:突破某网专利数据爬取的多重技术壁垒
  • 告别裸机点灯:用LVGL在STM32F4 Discovery板上做个炫酷的仪表盘(源码已开源)
  • 告别轮询:在S32K144上使用can_pal组件实现高效CAN中断接收与环形队列
  • AI Agent 长链工作流的最大隐形黑洞:Claude 提示缓存的架构纪律拆解
  • 训练数据来源合法吗?(深度拆解Stable Code、CodeLlama等模型的著作权灰色地带)
  • WeChatMsg完整教程:三步永久保存微信聊天记录的终极方案
  • Hermes Agent怎么部署?2026年阿里云计算巢/无影/轻量服务器部署图文教程及常见问题汇总
  • 保姆级教程:用Python多线程爆破CISCN2018 Java密码题中的‘弱随机数’(附完整代码)
  • OpenCDA实战:从零构建协同驾驶仿真场景与算法集成指南
  • 从SPI到IIC:7脚OLED屏幕接口改造实战指南
  • 【限时解禁】Gartner未公开评估报告节选:Top 8低代码平台AI就绪度排名,第3名意外反超OutSystems(含API粒度级生成延迟实测数据)
  • 告别‘一发一收’:用Wireshark抓包实战解析802.11n的Block ACK机制如何提升Wi-Fi速度
  • 如何在倒计时到达 1 后隐藏数字显示,同时继续运行至 -1
  • 生成式AI用户画像构建:为什么传统RFM彻底失效?——2024最新5维行为语义建模框架
  • 系统聚类实战:从距离定义到SPSS谱系图解析与K值优化
  • 千问3.5-2B图文理解实操手册:清晰图/模糊图/反光图/低对比度图四类适配策略
  • x86-64 汇编手撕 XOR 神经网络:从寄存器乘法到 FPU 指数运算的全链路底层复盘
  • WPF企业级界面架构决策:Fluent.Ribbon如何解决复杂业务界面的可维护性挑战
  • **发散创新:基于Python与TTS的语音合成系统实战解析**在人工智能快速发展的今天,**语音合成(T