代码
<script setup lang="ts">
import router from '@/router';
import * as THREE from 'three';
import { ref, type Ref, nextTick } from 'vue';
import { onMounted } from 'vue';
const props = defineProps({
title: String,
OnThreeLoaded: Function,
Tick: Function,
})
const handleClick = () => {
router.back();
}
const threeContainer: Ref<HTMLElement | null> = ref(null);
let renderer: THREE.WebGLRenderer | null = null;
let camera: THREE.PerspectiveCamera | null = null;
let scene: THREE.Scene | null = null;
let cube: THREE.Mesh | null = null;
onMounted(() => {
nextTick(() => {
if (!threeContainer.value) return
// 初始化场景
scene = new THREE.Scene()
// 初始化相机
camera = new THREE.PerspectiveCamera(75, threeContainer.value.offsetWidth / threeContainer.value.offsetHeight, 0.1, 1000)
camera.position.z = 5
//添加摄像机
scene.add(camera);
// 添加物体
const geometry = new THREE.BoxGeometry()
const material = new THREE.MeshBasicMaterial({ color: 0x00ff00 })
cube = new THREE.Mesh(geometry, material)
scene.add(cube)
// 初始化渲染器
renderer = new THREE.WebGLRenderer({ antialias: true })
renderer.setSize(threeContainer.value.offsetWidth, threeContainer.value.offsetHeight)
//新写法
renderer.setAnimationLoop(tick)
threeContainer.value.appendChild(renderer.domElement)
// 通知父组件
props.OnThreeLoaded?.(scene, camera, renderer)
// 启动渲染循环(旧写法)
// tick(0)
})
let previousTime = 0
const tick = (time: number) => {
if (renderer&&scene&&camera) {
const deltaTime = (time - previousTime)
if (cube)
cube.rotation.y += 0.001*deltaTime
//Tick
props.Tick?.(time, deltaTime);
renderer.render(scene!, camera!);
previousTime = time
//渲染旧写法
// window.requestAnimationFrame(tick)
}
}
})
</script>
模板
<template>
<div class="layout">
<div class="iconfont icon-guanbi" @click="handleClick"></div>
<div class="title">{{ props.title }}</div>
<div class="three-container" ref="threeContainer">
</div>
<slot>
</slot>
</div>
</template>
样式
<style scoped>
.three-container {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
}
.layout {
position: relative;
width: 100vw;
height: 100vh;
}
.icon-guanbi {
font-size: 30px;
position: absolute;
top: 10px;
left: 10px;
z-index: 1;
}
.icon-guanbi:hover,
.icon-guanbi:focus {
color: #ff0000;
font-size: 32px;
}
.icon-guanbi:active {
color: #2494da;
font-size: 30px;
}
.title {
position: absolute;
top: 10px;
left: 50px;
font-size: 20px;
font-weight: bold;
color: white;
z-index: 1;
}
</style>