threejs + vite + vue3 数字孪生简单案例
一、安装必要的软件3D项目创建 npm create vitelatest task-hub -- --template vue npm create vitelatest拉取最新版 Vite 脚手架创建项目 task-hub项目文件夹名称生成在当前目录 --分隔 npm 参数与 Vite 专属参数不能省略 --template vue指定模板为纯 Vue3不含 TS、JSX 等 npm install vue-router 安装路由 npm install three --save # three 生产依赖 npm install types/three -D # 类型声明 开发依赖 npm install ant-design-vue 业务 UI 组件库 npm install typescript --save-dev 等价 npm install typescript -D npm install stats.js //帧率监控性能监控 npm install types/stats.js -D //开发依赖 // 运行依赖页面要实际使用控制面板 Three.js/ WebGL 开发专用可视化调试控制面板快速拖拽修改参数不用反复改代码刷新页面。 专门调 Three.js、3D 场景、动画、光照、模型参数普通用户不会看到这个面板。 npm install dat.gui npm install types/dat.gui -D npm install gsap 补间动画二、文件内容文件结构如下tianhang:~/ThreejsEngineer$ tree -L 3 . ├── index.html ....... ├── package.json ├── package-lock.json ├── public │ ├── favicon.svg │ └── icons.svg ├── README.md ├── src │ ├── App.vue │ ├── assets │ │ ├── css │ │ └── img │ ├── components │ │ └── ThreeView.vue │ ├── lesson │ │ └── Home.vue │ ├── main │ │ └── main.js │ └── router │ └── index.ts └── vite.config.js tianhang:~/ThreejsEngineer$ ls index.html node_modules package.json package-lock.json public README.md src vite.config.js内容如下package.json内容 { name: task-hub, private: true, version: 0.0.0, type: module, scripts: { dev: vite, build: vite build, preview: vite preview --host }, dependencies: { ant-design-vue: ^4.2.6, dat.gui: ^0.7.9, gsap: ^3.15.0, stats.js: ^0.17.0, three: ^0.185.0, vue: ^3.5.39, vue-router: ^5.1.0 }, devDependencies: { types/stats.js: ^0.17.4, types/three: ^0.185.0, vitejs/plugin-vue: ^6.0.7, vue/tsconfig: ^0.9.1, typescript: ^6.0.3, vite: ^8.1.1, vue-tsc: ^3.3.6 } } index.html内容 !doctype html html langen head meta charsetUTF-8 / link relicon typeimage/svgxml href./src/assets/img/TSK.png / meta nameviewport contentwidthdevice-width, initial-scale1.0 / title工业系统/title /head body div idapp/div script typemodule src./src/main/main.js/script /body /html main.js 内容 import { createApp } from vue import ../assets/css/style.css import App from ../App.vue createApp(App).mount(#app) Home.vue 内容 template div h2Three.js 演示/h2 ThreeView / /div /template script setup langts import ThreeView from ../components/ThreeView.vue /script App.vue内容 script setup import Home from ./lesson/Home.vue /script template Home / /template ThreeView.vue内容 template !-- 专属容器不再直接挂body -- div refcanvasContainer stylewidth:100%;height:600px;border:1px solid #eee;/div /template script setup langts import { ref, onMounted, onUnmounted } from vue import * as THREE from three import { OrbitControls } from three/examples/jsm/controls/OrbitControls import { gsap } from gsap // DOM容器ref const canvasContainer refHTMLDivElement | null(null) // 全局场景变量统一管理卸载时销毁 let scene: THREE.Scene let camera: THREE.PerspectiveCamera let renderer: THREE.WebGLRenderer let controls: OrbitControls let cube: THREE.Mesh let animateId: number let gsapTween: gsap.core.Tween // 窗口resize处理函数 const handleResize () { if (!canvasContainer.value) return const width canvasContainer.value.clientWidth const height canvasContainer.value.clientHeight camera.aspect width / height camera.updateProjectionMatrix() renderer.setSize(width, height) renderer.setPixelRatio(window.devicePixelRatio) } // 双击全屏 const handleDblClick () { if (!document.fullscreenElement) { renderer.domElement.requestFullscreen() } else { document.exitFullscreen() } } // 渲染循环 const renderLoop () { animateId requestAnimationFrame(renderLoop) controls.update() renderer.render(scene, camera) } // 挂载时初始化3D场景 onMounted(() { if (!canvasContainer.value) return // 1. 场景 scene new THREE.Scene() // 2. 相机 camera new THREE.PerspectiveCamera( 75, canvasContainer.value.clientWidth / canvasContainer.value.clientHeight, 0.1, 1000 ) camera.position.set(0, 0, 10) scene.add(camera) // 3. 立方体 const boxGeo new THREE.BoxGeometry(1, 1, 1) const mat new THREE.MeshBasicMaterial({ color: 0xffff00 }) cube new THREE.Mesh(boxGeo, mat) scene.add(cube) // 4. 渲染器挂载到vue容器不是body renderer new THREE.WebGLRenderer() renderer.setSize(canvasContainer.value.clientWidth, canvasContainer.value.clientHeight) canvasContainer.value.appendChild(renderer.domElement) // 5. 轨道控制器 controls new OrbitControls(camera, renderer.domElement) controls.enableDamping true // 6. gsap动画 gsapTween gsap.to(cube.position, { x: 5, duration: 5, repeat: -1, yoyo: true, ease: bounce.out, onComplete: () console.log(动画完成), onStart: () console.log(动画开始) }) // 7. 坐标轴辅助 const axesHelper new THREE.AxesHelper(8) scene.add(axesHelper) // 8. 监听事件 window.addEventListener(resize, handleResize) renderer.domElement.addEventListener(dblclick, handleDblClick) // 启动渲染 renderLoop() }) // 组件销毁释放资源关键防止内存泄漏 onUnmounted(() { // 停止渲染循环 cancelAnimationFrame(animateId) // 停止gsap动画 gsapTween.kill() // 移除监听 window.removeEventListener(resize, handleResize) renderer.domElement.removeEventListener(dblclick, handleDblClick) // 销毁渲染器、几何体、材质释放显存 renderer.dispose() cube.geometry.dispose() if (Array.isArray(cube.material)) { cube.material.forEach(m m.dispose()) } else { cube.material.dispose() } }) /script三、服务器部署1文件打包npm run buildtianhang:~/ThreejsEngineer$ npm run build task-hub0.0.0 build vite build vite v8.1.2 building client environment for production... ✓ 21 modules transformed. computing gzip size... dist/index.html 0.48 kB │ gzip: 0.34 kB dist/assets/TSK-BnnPvGX4.png 10.62 kB dist/assets/index-Bzyp_i7E.css 0.04 kB │ gzip: 0.06 kB dist/assets/index-UVdWu6yE.js 671.57 kB │ gzip: 185.80 kB [plugin builtin:vite-reporter] (!) Some chunks are larger than 500 kB after minification. Consider: - Using dynamic import() to code-split the application - Use build.rolldownOptions.output.codeSplitting to improve chunking: https://rolldown.rs/reference/OutputOptions.codeSplitting - Adjust chunk size limit for this warning via build.chunkSizeWarningLimit. ✓ built in 672ms2文件传输/home/tian/ThreejsEngineer/dist/ 文件在主机的位置kickpi192.168.31.224:/home/kickpi/myvue3 服务器用户名ip地址、文件放置服务器的位置scp -r /home/tian/ThreejsEngineer/dist/ kickpi192.168.31.224:/home/kickpi/myvue33权限配置服务器第一次没起起来检查时权限问题做了如下操作sudo mkdir -p /www/myvue3 sudo cp -r /home/kickpi/myvue3/dist/* /www/myvue3/ sudo chown -R www-data:www-data /www/myvue3 sudo chmod -R 755 /www/myvue34安装服务器用到的命令如下sudo apt update sudo apt install nginx -y //安装服务器 nginx -v //查看版本 sudo systemctl start nginx # 启动服务 sudo systemctl enable nginx # 设置开机自启 sudo ufw allow 80/tcp # 放行80端口 **kickpi不用** sudo systemctl status nginx # 查看运行状态 sudo systemctl reload nginx.service #重新加载 更改文件后需要 sudo nginx -t # 校验配置语法5文件增加sudo vim /etc/nginx/conf.d/taskhub.confsudo vim /etc/nginx/conf.d/taskhub.conf 文件内容 server { listen 5210; # 填你的域名或服务器公网IP server_name myvue3.com 192.168.31.224; # 上传dist的目录 root /www/myvue3; index index.html; # 关键Vue Router history模式刷新404解决方案 location / { try_files $uri $uri/ /index.html; } # 静态资源缓存提升加载速度 location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg|woff2)$ { expires 7d; add_header Cache-Control public; } }四、内网访问展示