这是@PolygonParrot 之前给出的答案的后续。由于评论长度的限制,我不得不把我的答案放在这里。
非常感谢您的回答,@PolygonParrot。这对我帮助很大!根据您的演示代码,我发现将动画代码与 Vue 组件代码分开的关键是将正确的动画上下文传递给在 animation.js 中定义的模块。我认为我的第一次尝试失败可能是因为函数式编程的“闭包”特性,对于像我这样的古代程序员来说,这是一个痛苦的概念。我的animation.js 现在看起来像这样:
import * as THREE from 'three'
// passed in container id within which this animation will be shown
export function createBoxRotationContext(container) {
var ctx = new Object();
ctx.init = function init() {
ctx.container = container;
ctx.camera = new THREE.PerspectiveCamera(70, ctx.container.clientWidth/ctx.container.clientHeight, 0.01, 10);
ctx.camera.position.z = 1;
ctx.scene = new THREE.Scene();
let geometry = new THREE.BoxGeometry(0.3, 0.4, 0.5);
let material = new THREE.MeshNormalMaterial();
ctx.box = new THREE.Mesh(geometry, material);
ctx.fnhelper = new THREE.FaceNormalsHelper(ctx.box, 0.3, 0x0000ff, 0.1);
ctx.axes = new THREE.AxesHelper(5);
ctx.scene.add(ctx.box);
ctx.scene.add(ctx.axes);
ctx.scene.add(ctx.fnhelper);
ctx.renderer = new THREE.WebGLRenderer({antialias: true});
ctx.renderer.setSize(ctx.container.clientWidth, ctx.container.clientHeight);
ctx.container.appendChild(ctx.renderer.domElement);
},
ctx.animate = function animate() {
requestAnimationFrame(animate);
ctx.box.rotation.x += 0.01;
ctx.box.rotation.y += 0.02;
ctx.fnhelper.update();
ctx.renderer.render(ctx.scene, ctx.camera);
}
return ctx;
};
.vue 文件现在看起来像:
<script>
import * as animator from '@/components/sandbox/animation.js'
export default {
name: 'Sandbox',
data() {
return {
camera: null,
scene: null,
renderer: null,
mesh: null
}
},
mounted() {
let context = animator.createBoxRotationContext(
document.getElementById('three-sandbox')
);
context.init();
context.animate();
}
}
</script\>
随着我的场景通过添加更多内容而变得更大,我的 vue 模板可以保持干净并将动画逻辑隐藏在视图后面。我认为我在这里使用上下文看起来仍然很奇怪,但至少它现在很好地满足了我的目的。