发布时间:2026/7/11 12:01:53
Vue 3 + Three.js r164 项目实战:5步封装可复用3D场景组件(含响应式)
Vue 3 Three.js r164 工程化实战构建高复用3D场景组件的5个关键步骤在当今前端开发领域3D可视化需求正以前所未有的速度增长。从电商产品展示到数据可视化大屏从虚拟现实应用到游戏开发Three.js作为WebGL的友好封装库已经成为实现这些需求的首选工具。本文将带您深入探索如何基于Vue 3的组合式API和TypeScript构建一个高度可复用的3D场景组件。1. 环境准备与项目初始化在开始之前我们需要确保开发环境配置正确。与传统的Vue 2项目不同现代Vue 3项目通常采用Vite作为构建工具它能提供更快的冷启动和热更新速度。首先创建一个基于Vite的Vue 3项目npm create vitelatest vue-three-project --template vue-ts cd vue-three-project npm install three types/three项目结构建议如下src/ ├── components/ │ └── ThreeScene/ │ ├── ThreeScene.vue # 3D场景主组件 │ ├── composables/ # 组合式函数 │ │ ├── useRenderer.ts │ │ ├── useResize.ts │ └── types/ │ └── config.ts # 类型定义 ├── App.vue └── main.ts关键依赖版本要求Vue 3.3Three.js r164TypeScript 5.02. 核心组件架构设计一个优秀的3D场景组件应该具备清晰的接口定义和良好的封装性。我们将使用Vue 3的defineComponent和TypeScript来确保类型安全。首先定义组件Props类型// src/components/ThreeScene/types/config.ts export interface ThreeSceneProps { width?: number | string; // 画布宽度 height?: number | string; // 画布高度 backgroundColor?: string; // 背景色 cameraOptions?: { fov?: number; // 视野角度 near?: number; // 近裁剪面 far?: number; // 远裁剪面 position?: THREE.Vector3; // 相机位置 }; antialias?: boolean; // 是否开启抗锯齿 autoRotate?: boolean; // 是否自动旋转 }组件基础结构!-- src/components/ThreeScene/ThreeScene.vue -- script setup langts import { defineProps, onMounted, onUnmounted, ref } from vue import * as THREE from three import type { ThreeSceneProps } from ./types/config const props withDefaults(definePropsThreeSceneProps(), { width: 100%, height: 100%, backgroundColor: #000000, cameraOptions: () ({ fov: 75, near: 0.1, far: 1000, position: new THREE.Vector3(0, 0, 5) }), antialias: true, autoRotate: false }) const canvasRef refHTMLCanvasElement | null(null) // 其他逻辑... /script template div classscene-container canvas refcanvasRef/canvas /div /template style scoped .scene-container { position: relative; overflow: hidden; } canvas { display: block; width: v-bind(props.width); height: v-bind(props.height); } /style3. 响应式场景管理现代前端应用需要适应各种屏幕尺寸我们的3D场景也必须具备响应式能力。以下是实现响应式场景的关键步骤3.1 初始化Three.js核心要素// 在ThreeScene.vue的setup函数中 const scene new THREE.Scene() const camera new THREE.PerspectiveCamera( props.cameraOptions.fov, window.innerWidth / window.innerHeight, props.cameraOptions.near, props.cameraOptions.far ) camera.position.copy(props.cameraOptions.position) const renderer new THREE.WebGLRenderer({ canvas: canvasRef.value!, antialias: props.antialias, alpha: true }) renderer.setPixelRatio(window.devicePixelRatio) renderer.setClearColor(props.backgroundColor)3.2 实现响应式调整const handleResize () { if (!canvasRef.value) return const width canvasRef.value.clientWidth const height canvasRef.value.clientHeight camera.aspect width / height camera.updateProjectionMatrix() renderer.setSize(width, height, false) } onMounted(() { window.addEventListener(resize, handleResize) handleResize() // 初始调整 }) onUnmounted(() { window.removeEventListener(resize, handleResize) })3.3 动画循环管理const clock new THREE.Clock() let animationId: number const startAnimationLoop () { const animate () { animationId requestAnimationFrame(animate) const delta clock.getDelta() // 这里可以添加自定义动画逻辑 if (props.autoRotate) { scene.rotation.y delta * 0.5 } renderer.render(scene, camera) } animate() } onMounted(() { startAnimationLoop() }) onUnmounted(() { cancelAnimationFrame(animationId) })4. 高级功能封装4.1 轨道控制器集成轨道控制器(OrbitControls)是Three.js中常用的交互控制工具允许用户通过鼠标旋转、平移和缩放场景。import { OrbitControls } from three/examples/jsm/controls/OrbitControls const initControls () { const controls new OrbitControls(camera, renderer.domElement) controls.enableDamping true controls.dampingFactor 0.05 return { controls, update: () controls.update() } } // 在动画循环中调用controls.update()4.2 资源加载与管理3D场景通常需要加载各种资源(纹理、模型等)我们需要实现统一的加载和管理机制。const loadTexture (url: string): PromiseTHREE.Texture { return new Promise((resolve, reject) { const loader new THREE.TextureLoader() loader.load( url, texture resolve(texture), undefined, error reject(error) ) }) } const loadModel async (url: string): PromiseTHREE.Group { const loader new THREE.GLTFLoader() const gltf await loader.loadAsync(url) return gltf.scene }4.3 性能优化技巧优化技术实现方式适用场景InstancedMesh使用THREE.InstancedMesh大量相同几何体LOD (Level of Detail)创建不同细节级别的模型复杂场景Frustum Culling启用frustumCulled属性大型开放世界GPU加速使用WebGLRenderer的powerPreference所有3D场景// 实例化网格示例 const createInstancedCubes (count: number) { const geometry new THREE.BoxGeometry(1, 1, 1) const material new THREE.MeshBasicMaterial({ color: 0x00ff00 }) const mesh new THREE.InstancedMesh(geometry, material, count) const matrix new THREE.Matrix4() for (let i 0; i count; i) { matrix.setPosition( Math.random() * 20 - 10, Math.random() * 20 - 10, Math.random() * 20 - 10 ) mesh.setMatrixAt(i, matrix) } scene.add(mesh) }5. 组件化与复用实践5.1 场景对象管理使用Vue的响应式系统管理3D对象const objects refTHREE.Object3D[]([]) const addObject (obj: THREE.Object3D) { scene.add(obj) objects.value.push(obj) } const removeObject (obj: THREE.Object3D) { scene.remove(obj) objects.value objects.value.filter(o o ! obj) } const clearScene () { objects.value.forEach(obj scene.remove(obj)) objects.value [] }5.2 组合式函数抽象将Three.js的核心功能抽象为可复用的组合式函数// src/components/ThreeScene/composables/useRenderer.ts export function useRenderer(canvas: RefHTMLCanvasElement, options: RendererOptions) { const renderer shallowRefTHREE.WebGLRenderer() onMounted(() { renderer.value new THREE.WebGLRenderer({ canvas: canvas.value!, antialias: options.antialias, alpha: options.alpha }) renderer.value.setPixelRatio(window.devicePixelRatio) renderer.value.setSize(canvas.value!.clientWidth, canvas.value!.clientHeight) }) onUnmounted(() { renderer.value?.dispose() }) return { renderer } }5.3 完整组件示例script setup langts import { ref, onMounted, onUnmounted, watch } from vue import * as THREE from three import { OrbitControls } from three/examples/jsm/controls/OrbitControls import { useRenderer } from ./composables/useRenderer import { useResize } from ./composables/useResize const props defineProps({ // ...之前的props定义 }) const canvasRef refHTMLCanvasElement | null(null) const scene new THREE.Scene() const camera new THREE.PerspectiveCamera( props.cameraOptions.fov, window.innerWidth / window.innerHeight, props.cameraOptions.near, props.cameraOptions.far ) const { renderer } useRenderer(canvasRef, { antialias: props.antialias, alpha: true }) const { handleResize } useResize(canvasRef, camera, renderer) // 初始化场景内容 const initScene () { // 添加光源 const ambientLight new THREE.AmbientLight(0x404040) scene.add(ambientLight) const directionalLight new THREE.DirectionalLight(0xffffff, 0.5) directionalLight.position.set(1, 1, 1) scene.add(directionalLight) // 添加辅助工具 const axesHelper new THREE.AxesHelper(5) scene.add(axesHelper) } // 动画循环 const animate () { requestAnimationFrame(animate) renderer.value?.render(scene, camera) } onMounted(() { initScene() animate() window.addEventListener(resize, handleResize) }) onUnmounted(() { window.removeEventListener(resize, handleResize) // 清理资源 scene.traverse(child { if (child instanceof THREE.Mesh) { child.geometry.dispose() if (Array.isArray(child.material)) { child.material.forEach(m m.dispose()) } else { child.material.dispose() } } }) }) /script进阶技巧与性能优化内存管理与资源释放Three.js创建的几何体、材质和纹理都需要手动释放内存const disposeResources () { scene.traverse(child { if (child instanceof THREE.Mesh) { child.geometry.dispose() if (Array.isArray(child.material)) { child.material.forEach(m m.dispose()) } else { child.material.dispose() } } else if (child instanceof THREE.Light) { child.dispose() } }) renderer.value?.dispose() renderer.value?.forceContextLoss() }响应式属性处理使用watch监听props变化并更新场景watch(() props.backgroundColor, (newColor) { if (renderer.value) { renderer.value.setClearColor(newColor) } }) watch(() props.autoRotate, (enabled) { // 更新自动旋转状态 })性能监控集成stats.js进行性能监控import Stats from stats.js const stats new Stats() stats.showPanel(0) // 0: fps, 1: ms, 2: mb onMounted(() { document.body.appendChild(stats.dom) const animate () { stats.begin() // 渲染逻辑... stats.end() requestAnimationFrame(animate) } animate() }) onUnmounted(() { document.body.removeChild(stats.dom) })实际应用案例商品3D展示组件script setup langts import { ref, onMounted } from vue import { useThreeScene } from ./ThreeScene/useThreeScene const { scene, loadModel } useThreeScene() const loading ref(true) const error ref(null) onMounted(async () { try { const productModel await loadModel(/models/product.glb) productModel.scale.set(0.5, 0.5, 0.5) scene.add(productModel) } catch (err) { error.value err } finally { loading.value false } }) /script template div classproduct-viewer ThreeScene v-if!loading !error :auto-rotatetrue slot namecontrols/slot /ThreeScene div v-ifloading classloading加载中.../div div v-iferror classerror加载失败: {{ error.message }}/div /div /template数据可视化大屏组件const createBarChart (data: number[], colors: string[]) { const group new THREE.Group() data.forEach((value, i) { const geometry new THREE.BoxGeometry(1, value, 1) const material new THREE.MeshBasicMaterial({ color: new THREE.Color(colors[i]) }) const bar new THREE.Mesh(geometry, material) bar.position.x i * 2 - data.length bar.position.y value / 2 group.add(bar) }) return group }

相关新闻

CANN Runtime日志配置查看
2026/7/11 12:01:53

CANN Runtime日志配置查看

查看日志配置文件 【免费下载链接】runtime 本项目提供CANN运行时组件和维测功能组件。 项目地址: https://gitcode.com/cann/runtime 本节介绍Device侧的日志配置文件。该文件中记录了Device侧系统类日志的日志级别、日志输出路径、日志数量、单个日志文件大小等配置信…

阅读更多
ChatGPT-Image2图像生成实战:从免费使用到工作流搭建
2026/7/11 12:01:53

ChatGPT-Image2图像生成实战:从免费使用到工作流搭建

上周帮一个做内容的朋友处理图片素材,他给我发来一堆需求:要生成带特定文字的横幅、要统一风格的插画、还要把几个产品图重新组合。我问他为什么不直接用现有的AI图像工具,他说试过几个,要么文字渲染有问题,要么风格控…

阅读更多
微信聊天记录永久备份终极指南:3步完成数据主权掌控
2026/7/11 11:01:53

微信聊天记录永久备份终极指南:3步完成数据主权掌控

微信聊天记录永久备份终极指南:3步完成数据主权掌控 【免费下载链接】WeChatMsg 提取微信聊天记录,将其导出成HTML、Word、CSV文档永久保存,对聊天记录进行分析生成年度聊天报告 项目地址: https://gitcode.com/GitHub_Trending/we/WeChatM…

阅读更多
终极GitHub下载解决方案:如何快速打包任意文件或文件夹
2026/7/11 12:01:53

终极GitHub下载解决方案:如何快速打包任意文件或文件夹

终极GitHub下载解决方案:如何快速打包任意文件或文件夹 【免费下载链接】DownGit github 资源打包下载工具 项目地址: https://gitcode.com/gh_mirrors/dow/DownGit 还在为GitHub上庞大的开源项目而烦恼吗?每次只想下载某个配置文件或特定模块&am…

阅读更多
Next.js 14 + Cursor IDE深度协同开发指南(企业级SSR/ISR/AI调试闭环实践)
2026/7/11 12:01:53

Next.js 14 + Cursor IDE深度协同开发指南(企业级SSR/ISR/AI调试闭环实践)

更多请点击: https://codechina.net 第一章:Next.js 14 Cursor IDE协同开发全景概览 Next.js 14 引入了 App Router 默认启用、React Server Components 深度集成、Partial Prerendering(PPR)实验性支持以及更智能的编译缓存机制…

阅读更多
Vue 3 + Three.js r164 项目实战:5步封装可复用3D场景组件(含响应式)
2026/7/11 12:01:53

Vue 3 + Three.js r164 项目实战:5步封装可复用3D场景组件(含响应式)

Vue 3 Three.js r164 工程化实战:构建高复用3D场景组件的5个关键步骤在当今前端开发领域,3D可视化需求正以前所未有的速度增长。从电商产品展示到数据可视化大屏,从虚拟现实应用到游戏开发,Three.js作为WebGL的友好封装库&#x…

阅读更多
CANN Runtime日志配置查看
2026/7/11 12:01:53

CANN Runtime日志配置查看

查看日志配置文件 【免费下载链接】runtime 本项目提供CANN运行时组件和维测功能组件。 项目地址: https://gitcode.com/cann/runtime 本节介绍Device侧的日志配置文件。该文件中记录了Device侧系统类日志的日志级别、日志输出路径、日志数量、单个日志文件大小等配置信…

阅读更多
ChatGPT-Image2图像生成实战:从免费使用到工作流搭建
2026/7/11 12:01:53

ChatGPT-Image2图像生成实战:从免费使用到工作流搭建

上周帮一个做内容的朋友处理图片素材,他给我发来一堆需求:要生成带特定文字的横幅、要统一风格的插画、还要把几个产品图重新组合。我问他为什么不直接用现有的AI图像工具,他说试过几个,要么文字渲染有问题,要么风格控…

阅读更多
微信聊天记录永久备份终极指南:3步完成数据主权掌控
2026/7/11 11:01:53

微信聊天记录永久备份终极指南:3步完成数据主权掌控

微信聊天记录永久备份终极指南:3步完成数据主权掌控 【免费下载链接】WeChatMsg 提取微信聊天记录,将其导出成HTML、Word、CSV文档永久保存,对聊天记录进行分析生成年度聊天报告 项目地址: https://gitcode.com/GitHub_Trending/we/WeChatM…

阅读更多
通达OA SQL注入漏洞深度剖析:从手工注入到自动化利用与防御
2026/7/11 9:29:02

通达OA SQL注入漏洞深度剖析:从手工注入到自动化利用与防御

1. 项目概述与漏洞背景最近在梳理一些历史OA系统的安全风险时,通达OA v11.6版本中的一个老漏洞又进入了我的视线。这个漏洞位于/general/bi_design/appcenter/report_bi.func.php文件中,是一个典型的SQL注入点。虽然这个漏洞的利用方式看起来并不复杂&am…

阅读更多
3步彻底解决Windows右键菜单混乱问题:ContextMenuManager使用全攻略
2026/7/11 9:29:02

3步彻底解决Windows右键菜单混乱问题:ContextMenuManager使用全攻略

3步彻底解决Windows右键菜单混乱问题:ContextMenuManager使用全攻略 【免费下载链接】ContextMenuManager 🖱️ 纯粹的Windows右键菜单管理程序 项目地址: https://gitcode.com/gh_mirrors/co/ContextMenuManager 你是否曾为Windows右键菜单中那些…

阅读更多
GXDE OS下Wayland兼容性实战:从deepin-mutter原理到VMware Tools修复
2026/7/11 9:29:01

GXDE OS下Wayland兼容性实战:从deepin-mutter原理到VMware Tools修复

如果你正在用 GXDE OS 或者任何基于 Deepin 的发行版,并且遇到了“检测到窗口系统采用 Wayland 协议,程序即将退出”这类弹窗,或者发现 VMware Tools 在 Ubuntu 24.04 这类默认 Wayland 的系统上启动失败,那这篇文章就是为你准备的…

阅读更多
PostgreSQL 备份与恢复实战:从 pg_dump 到时间点恢复的生产级方案
2026/7/11 0:01:31

PostgreSQL 备份与恢复实战:从 pg_dump 到时间点恢复的生产级方案

PostgreSQL 备份与恢复实战:从 pg_dump 到时间点恢复的生产级方案 一、数据库备份最容易被忽略的问题,不是「有没有做备份」,而是「备份能不能恢复、恢复要多久、以及恢复后的数据对不对」 很多团队做数据库备份的方式是「写个 cron job&am…

阅读更多
工业信号干扰处理与FOD4216光耦应用实战
2026/7/11 0:01:31

工业信号干扰处理与FOD4216光耦应用实战

1. 工业环境中的信号干扰挑战在工业自动化领域,信号采集的准确性直接关系到整个控制系统的可靠性。典型的工业现场充斥着各种干扰源:大功率电机启停产生的电磁干扰、变频器工作产生的高频噪声、继电器触点火花放电,以及长距离传输引入的共模干…

阅读更多
每日穿搭助手:鸿蒙AI应用开发实战——AI衣橱,每日穿搭不再愁
2026/7/11 0:01:31

每日穿搭助手:鸿蒙AI应用开发实战——AI衣橱,每日穿搭不再愁

每日穿搭助手:鸿蒙AI应用开发实战——AI衣橱,每日穿搭不再愁 一、引言 每天早上打开衣柜,面对满柜的衣服却不知道穿什么——这是无数人的日常困扰。气温变化、场合差异、风格偏好,这些因素交织在一起,让"穿什么&q…

阅读更多
基于Dify与DeepSeek构建私有知识库问答系统实战指南
2026/7/11 9:29:01

基于Dify与DeepSeek构建私有知识库问答系统实战指南

在业务中快速构建一个能理解私有文档、准确回答专业问题的智能助手,是很多开发团队面临的共同挑战。传统方案往往需要从零开始搭建复杂的 RAG(检索增强生成)系统,涉及文档解析、向量化、检索、大模型调用等多个环节,整…

阅读更多
FAE放射组学分析工具:医学影像特征探索的完整解决方案
2026/7/11 9:29:01

FAE放射组学分析工具:医学影像特征探索的完整解决方案

FAE放射组学分析工具:医学影像特征探索的完整解决方案 【免费下载链接】FAE FeAture Explorer 项目地址: https://gitcode.com/gh_mirrors/fae/FAE 你是否曾经面对海量医学影像数据感到无从下手?想要从CT、MRI等影像中提取有价值的定量特征&#…

阅读更多
DesktopNaotu:你的终极离线思维导图解决方案,告别网络依赖!
2026/7/11 9:29:01

DesktopNaotu:你的终极离线思维导图解决方案,告别网络依赖!

DesktopNaotu:你的终极离线思维导图解决方案,告别网络依赖! 【免费下载链接】DesktopNaotu 桌面版脑图 (百度脑图离线版,思维导图) 跨平台支持 Windows/Linux/Mac OS. (A cross-platform multilingual Mind Map Tool) 项目地址:…

阅读更多