使用 Vue 3、TypeScript 和 Three.js 封装3D动画框架

在现代Web开发中,结合Vue.js的响应式特性与Three.js的强大3D渲染能力,可以创造出令人印象深刻的3D动画效果。本篇博客将介绍如何使用Vue 3、TypeScript和Three.js来封装一个可重用的3D动画框架。

1. 介绍

Vue 3

Vue 3 是Vue框架的最新版本,它引入了许多改进,包括更好的性能、更简洁的API以及新的响应性系统。

TypeScript

TypeScript 是JavaScript的一个超集,它可以提供静态类型检查和编译时错误检测,有助于大型项目的维护和开发效率提升。

Three.js

Three.js 是一个基于WebGL的3D图形库,它简化了复杂的WebGL API,使得开发者能够更容易地创建和显示3D图形。

2. 开发环境准备

确保安装了以下软件:

  • Node.js(推荐使用最新的LTS版本)
  • npm 或 yarn

安装必要的包:

bash

深色版本

1npm install -g @vue/cli
2npm install

初始化Vue 3项目:

bash

深色版本

1vue create my-project
2cd my-project

选择使用TypeScript和Vue 3的选项。然后安装Three.js:

bash

深色版本

1npm install three

3. 创建基本的3D组件

我们从创建一个基础的3D组件开始,这个组件可以作为所有3D元素的基础。

3.1 创建3D组件

src/components/ 目录下创建 Base3DComponent.vue 文件:

vue

深色版本

1<template>
2  <div ref="containerRef" />
3</template>
4
5<script lang="ts">
6import { defineComponent, onMounted, onUnmounted, ref } from 'vue';
7import * as THREE from 'three';
8
9export default defineComponent({
10  name: 'Base3DComponent',
11  setup() {
12    const containerRef = ref<HTMLDivElement | null>(null);
13
14    let renderer: THREE.WebGLRenderer | null = null;
15    let scene: THREE.Scene | null = null;
16    let camera: THREE.PerspectiveCamera | null = null;
17
18    const init = () => {
19      renderer = new THREE.WebGLRenderer({ antialias: true });
20      renderer.setSize(containerRef.value!.clientWidth, containerRef.value!.clientHeight);
21      renderer.setPixelRatio(window.devicePixelRatio);
22      containerRef.value!.appendChild(renderer.domElement);
23
24      scene = new THREE.Scene();
25
26      camera = new THREE.PerspectiveCamera(
27        75,
28        containerRef.value!.clientWidth / containerRef.value!.clientHeight,
29        0.1,
30        1000
31      );
32      camera.position.z = 5;
33
34      const geometry = new THREE.BoxGeometry(1, 1, 1);
35      const material = new THREE.MeshBasicMaterial({ color: 0x00ff00 });
36      const cube = new THREE.Mesh(geometry, material);
37      scene!.add(cube);
38
39      const animate = () => {
40        requestAnimationFrame(animate);
41        if (cube) cube.rotation.x += 0.01;
42        if (cube) cube.rotation.y += 0.01;
43        if (renderer) renderer.render(scene!, camera!);
44      };
45
46      animate();
47    };
48
49    onMounted(() => {
50      if (containerRef.value) {
51        init();
52      }
53    });
54
55    onUnmounted(() => {
56      if (renderer) {
57        renderer.dispose();
58      }
59    });
60
61    return {
62      containerRef,
63    };
64  },
65});
66</script>

3.2 使用3D组件

App.vue 中使用 Base3DComponent 组件:

vue

深色版本

1<template>
2  <div id="app">
3    <base-3d-component />
4  </div>
5</template>
6
7<script lang="ts">
8import Base3DComponent from './components/Base3DComponent.vue';
9
10export default {
11  components: {
12    Base3DComponent,
13  },
14};
15</script>

4. 封装高级3D组件

4.1 创建可配置的3D组件

让我们扩展 Base3DComponent,使其可以接受属性来配置不同的3D对象。

更新 Base3DComponent.vue

vue

深色版本

1<template>
2  <div ref="containerRef" />
3</template>
4
5<script lang="ts">
6import { defineComponent, onMounted, onUnmounted, ref } from 'vue';
7import * as THREE from 'three';
8
9export default defineComponent({
10  name: 'Base3DComponent',
11  props: {
12    width: {
13      type: Number,
14      default: 1,
15    },
16    height: {
17      type: Number,
18      default: 1,
19    },
20    depth: {
21      type: Number,
22      default: 1,
23    },
24    color: {
25      type: String,
26      default: '#00ff00',
27    },
28  },
29  setup(props) {
30    const containerRef = ref<HTMLDivElement | null>(null);
31
32    let renderer: THREE.WebGLRenderer | null = null;
33    let scene: THREE.Scene | null = null;
34    let camera: THREE.PerspectiveCamera | null = null;
35
36    const init = () => {
37      renderer = new THREE.WebGLRenderer({ antialias: true });
38      renderer.setSize(containerRef.value!.clientWidth, containerRef.value!.clientHeight);
39      renderer.setPixelRatio(window.devicePixelRatio);
40      containerRef.value!.appendChild(renderer.domElement);
41
42      scene = new THREE.Scene();
43
44      camera = new THREE.PerspectiveCamera(
45        75,
46        containerRef.value!.clientWidth / containerRef.value!.clientHeight,
47        0.1,
48        1000
49      );
50      camera.position.z = 5;
51
52      const geometry = new THREE.BoxGeometry(props.width, props.height, props.depth);
53      const material = new THREE.MeshBasicMaterial({ color: props.color });
54      const cube = new THREE.Mesh(geometry, material);
55      scene!.add(cube);
56
57      const animate = () => {
58        requestAnimationFrame(animate);
59        if (cube) cube.rotation.x += 0.01;
60        if (cube) cube.rotation.y += 0.01;
61        if (renderer) renderer.render(scene!, camera!);
62      };
63
64      animate();
65    };
66
67    onMounted(() => {
68      if (containerRef.value) {
69        init();
70      }
71    });
72
73    onUnmounted(() => {
74      if (renderer) {
75        renderer.dispose();
76      }
77    });
78
79    return {
80      containerRef,
81    };
82  },
83});
84</script>

4.2 使用配置化的3D组件

App.vue 中使用带有属性的 Base3DComponent

vue

深色版本

1<template>
2  <div id="app">
3    <base-3d-component :width="2" :height="2" :depth="2" :color="#ff0000" />
4  </div>
5</template>
6
7<script lang="ts">
8import Base3DComponent from './components/Base3DComponent.vue';
9
10export default {
11  components: {
12    Base3DComponent,
13  },
14};
15</script>

5. 封装可复用的3D动画框架

为了更好地管理3D对象和动画,我们可以进一步抽象出一个更通用的3D框架。

5.1 创建3D框架类

创建一个 src/utils/ThreeFramework.ts 文件:

typescript

深色版本

1import * as THREE from 'three';
2
3export class ThreeFramework {
4  private scene: THREE.Scene;
5  private camera: THREE.PerspectiveCamera;
6  private renderer: THREE.WebGLRenderer;
7  private container: HTMLDivElement;
8
9  constructor(container: HTMLDivElement, width: number, height: number) {
10    this.container = container;
11    this.scene = new THREE.Scene();
12    this.camera = new THREE.PerspectiveCamera(75, width / height, 0.1, 1000);
13    this.camera.position.z = 5;
14
15    this.renderer = new THREE.WebGLRenderer({ antialias: true });
16    this.renderer.setSize(width, height);
17    this.renderer.setPixelRatio(window.devicePixelRatio);
18    container.appendChild(this.renderer.domElement);
19  }
20
21  public addMesh(mesh: THREE.Mesh): void {
22    this.scene.add(mesh);
23  }
24
25  public removeMesh(mesh: THREE.Mesh): void {
26    this.scene.remove(mesh);
27  }
28
29  public start(): void {
30    const animate = () => {
31      requestAnimationFrame(animate);
32      this.render();
33    };
34    animate();
35  }
36
37  private render(): void {
38    this.renderer.render(this.scene, this.camera);
39  }
40}

5.2 更新3D组件以使用框架

修改 Base3DComponent.vue,以使用 ThreeFramework 类:

vue

深色版本

1<template>
2  <div ref="containerRef" />
3</template>
4
5<script lang="ts">
6import { defineComponent, onMounted, onUnmounted, ref } from 'vue';
7import * as THREE from 'three';
8import { ThreeFramework } from '../utils/ThreeFramework';
9
10export default defineComponent({
11  name: 'Base3DComponent',
12  props: {
13    width: {
14      type: Number,
15      default: 1,
16    },
17    height: {
18      type: Number,
19      default: 1,
20    },
21    depth: {
22      type: Number,
23      default: 1,
24    },
25    color: {
26      type: String,
27      default: '#00ff00',
28    },
29  },
30  setup(props) {
31    const containerRef = ref<HTMLDivElement | null>(null);
32
33    let framework: ThreeFramework | null = null;
34    let cube: THREE.Mesh | null = null;
35
36    const init = () => {
37      framework = new ThreeFramework(containerRef.value!, window.innerWidth, window.innerHeight);
38
39      const geometry = new THREE.BoxGeometry(props.width, props.height, props.depth);
40      const material = new THREE.MeshBasicMaterial({ color: props.color });
41      cube = new THREE.Mesh(geometry, material);
42
43      framework.addMesh(cube);
44
45      framework.start();
46
47      const animate = () => {
48        requestAnimationFrame(animate);
49        if (cube) cube.rotation.x += 0.01;
50        if (cube) cube.rotation.y += 0.01;
51      };
52
53      animate();
54    };
55
56    onMounted(() => {
57      if (containerRef.value) {
58        init();
59      }
60    });
61
62    onUnmounted(() => {
63      if (framework) {
64        framework.removeMesh(cube!);
65      }
66    });
67
68    return {
69      containerRef,
70    };
71  },
72});
73</script>

6. 总结

通过上述步骤,我们创建了一个基于Vue 3、TypeScript和Three.js的3D动画框架。这个框架可以方便地添加、移除3D对象,并且支持自定义配置。你可以在此基础上继续扩展更多的功能,如用户交互、碰撞检测等。

  • 4
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值