简介:本文详细介绍如何在Vue3项目中集成Three.js实现3D物体缩放动画,包含环境配置、基础动画实现、性能优化及交互增强等核心内容,适合前端开发者及3D可视化需求者。
Vue3的Composition API与Three.js的3D渲染能力形成完美互补:Vue负责状态管理与UI交互,Three.js处理3D场景渲染。这种组合特别适合需要动态3D展示的应用场景,如产品展示、数据可视化等。
项目初始化:
npm init vue@latest vue-threejs-democd vue-threejs-demonpm install
Three.js安装:
npm install three @types/three --save
TypeScript配置(推荐):
在tsconfig.json中添加:
{"compilerOptions": {"types": ["three"]}}
import * as THREE from 'three';import { onMounted, ref } from 'vue';const setupScene = () => {// 1. 创建场景const scene = new THREE.Scene();scene.background = new THREE.Color(0xf0f0f0);// 2. 创建相机const camera = new THREE.PerspectiveCamera(75,window.innerWidth / window.innerHeight,0.1,1000);camera.position.z = 5;// 3. 创建渲染器const renderer = new THREE.WebGLRenderer({ antialias: true });renderer.setSize(window.innerWidth, window.innerHeight);document.body.appendChild(renderer.domElement);return { scene, camera, renderer };};
const createScalableBox = (scene: THREE.Scene) => {const geometry = new THREE.BoxGeometry(1, 1, 1);const material = new THREE.MeshBasicMaterial({color: 0x00ff00,wireframe: true});const cube = new THREE.Mesh(geometry, material);scene.add(cube);// 缩放动画函数const animateScale = (timestamp: number) => {const scale = 1 + Math.sin(timestamp * 0.001) * 0.5;cube.scale.set(scale, scale, scale);};return { cube, animateScale };};
const animate = (scene: THREE.Scene,camera: THREE.PerspectiveCamera,renderer: THREE.WebGLRenderer,animateFunc: (timestamp: number) => void) => {const clock = new THREE.Clock();const renderLoop = (timestamp: number) => {requestAnimationFrame(renderLoop);// 计算自上一帧的时间差const delta = clock.getDelta();// 执行自定义动画animateFunc(timestamp);renderer.render(scene, camera);};requestAnimationFrame(renderLoop);};
<template><div ref="container" class="three-container"></div></template><script lang="ts" setup>import * as THREE from 'three';import { onMounted, ref, watch } from 'vue';const props = defineProps<{scaleFactor: number;animationSpeed: number;}>();const container = ref<HTMLElement>();let scene: THREE.Scene;let camera: THREE.PerspectiveCamera;let renderer: THREE.WebGLRenderer;let cube: THREE.Mesh;onMounted(() => {if (!container.value) return;// 初始化场景({ scene, camera, renderer } = setupScene());({ cube } = createScalableBox(scene));animate();});watch(() => props.scaleFactor, (newVal) => {cube.scale.set(newVal, newVal, newVal);});// ...(包含之前定义的setupScene和createScalableBox函数)</script><style scoped>.three-container {width: 100%;height: 100vh;position: fixed;top: 0;left: 0;}</style>
<template><div><inputtype="range"v-model="scaleFactor"min="0.5"max="2"step="0.1"><ThreeJSContainer:scale-factor="scaleFactor":animation-speed="animationSpeed"/></div></template><script lang="ts" setup>import { ref } from 'vue';import ThreeJSContainer from './ThreeJSContainer.vue';const scaleFactor = ref(1);const animationSpeed = ref(0.001);</script>
import { Easing } from 'tween.js';const applyEasing = (cube: THREE.Mesh, targetScale: number, duration: number) => {let startTime: number;const startScale = cube.scale.x;const animate = (timestamp: number) => {if (!startTime) startTime = timestamp;const elapsed = timestamp - startTime;const progress = Math.min(elapsed / duration, 1);// 使用三次缓动const easedProgress = Easing.Cubic.InOut(progress);const currentScale = startScale + (targetScale - startScale) * easedProgress;cube.scale.set(currentScale, currentScale, currentScale);if (progress < 1) {requestAnimationFrame(animate);}};requestAnimationFrame(animate);};
const createMultipleCubes = (scene: THREE.Scene) => {const cubes: THREE.Mesh[] = [];const colors = [0xff0000, 0x00ff00, 0x0000ff];colors.forEach((color, index) => {const geometry = new THREE.BoxGeometry(0.8, 0.8, 0.8);const material = new THREE.MeshBasicMaterial({ color });const cube = new THREE.Mesh(geometry, material);// 不同位置和初始缩放cube.position.x = (index - 1) * 2;cube.scale.set(0.5 + index * 0.2, 0.5 + index * 0.2, 0.5 + index * 0.2);scene.add(cube);cubes.push(cube);});return cubes;};const animateMultipleCubes = (cubes: THREE.Mesh[], timestamp: number) => {cubes.forEach((cube, index) => {const phase = timestamp * 0.0005 + index;const scale = 0.8 + Math.sin(phase) * 0.3;cube.scale.set(scale, scale, scale);});};
按需渲染:
let lastTime = 0;const render = (timestamp: number) => {if (timestamp - lastTime < 16) return; // 约60FPSlastTime = timestamp;// 渲染逻辑...};
及时移除不再使用的对象:
const removeObject = (scene: THREE.Scene, object: THREE.Object3D) => {scene.remove(object);// 对于复杂对象,需要手动释放几何体和材质if (object.geometry) object.geometry.dispose();if (object.material) object.material.dispose();};
对象池模式:
```typescript
const cubePool: THREE.Mesh[] = [];
const getCubeFromPool = (scene: THREE.Scene) => {
if (cubePool.length > 0) {
const cube = cubePool.pop()!;
scene.add(cube);
return cube;
}
// 创建新立方体…
};
# 六、完整项目集成方案## 6.1 项目结构建议
src/
├── components/
│ ├── ThreeScene.vue # 主场景组件
│ └── AnimatedObject.vue # 可动画对象组件
├── composables/
│ └── useThree.ts # Three.js逻辑封装
├── utils/
│ └── animationUtils.ts # 动画工具函数
└── App.vue # 根组件
## 6.2 响应式适配实现```typescriptconst handleResize = (camera: THREE.PerspectiveCamera,renderer: THREE.WebGLRenderer) => {const resize = () => {camera.aspect = window.innerWidth / window.innerHeight;camera.updateProjectionMatrix();renderer.setSize(window.innerWidth, window.innerHeight);};window.addEventListener('resize', resize);// 组件卸载时移除监听onUnmounted(() => {window.removeEventListener('resize', resize);});};
stats.js监控FPSTHREE.ShaderMaterial替代多个MeshBasicMaterial触摸事件处理:
const setupTouchControls = (cube: THREE.Mesh) => {let touchStartScale = 1;const onTouchStart = (e: TouchEvent) => {if (e.touches.length === 2) {// 记录初始双指距离}};const onTouchMove = (e: TouchEvent) => {if (e.touches.length === 2) {const dx = e.touches[0].clientX - e.touches[1].clientX;const dy = e.touches[0].clientY - e.touches[1].clientY;const distance = Math.sqrt(dx * dx + dy * dy);// 根据距离变化调整缩放}};// 添加事件监听...};
性能模式设置:
const renderer = new THREE.WebGLRenderer({antialias: true,powerPreference: "high-performance" // 优先性能});
通过本文的详细指导,开发者可以系统掌握Vue3与Three.js结合实现3D物体缩放动画的全流程技术。从基础环境搭建到高级动画控制,再到性能优化策略,每个环节都提供了可落地的解决方案。建议开发者在实际项目中先实现基础功能,再逐步添加复杂动画和交互效果,最终构建出流畅、高效的3D可视化应用。