javascript vue组件中导入和使用three.js库

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/47849626/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-29 07:37:53  来源:igfitidea点击:

Import and use three.js library in vue component

javascriptimportvue.jsthree.jsshared-libraries

提问by ItsShowtime

Could someone please explain me how I correctlyimport and use the three.js library in a vue component?

有人可以解释一下我如何在 vue 组件中正确导入和使用 Three.js 库吗?

After many many searches It became clear to me that most people use the following line to import three.js in a vue component, however I think it's outdated (usef for older three.js document orused in older vue versions).

经过多次搜索我很清楚大多数人使用以下行在 vue 组件中导入three.js,但是我认为它已经过时了(用于较旧的three.js文档在较旧的vue版本中使用)。

import * as THREE from './js/three.js';

Unfortunately this doesn't seem to work for me as I get the following warnings when compiling my vue project afterwards. (Note that the project actually doesn't compile correctly and I get an empty file when I browse to it). enter image description here

不幸的是,这似乎对我不起作用,因为我在之后编译我的 vue 项目时收到以下警告。(请注意,该项目实际上没有正确编译,当我浏览它时得到一个空文件)。 在此处输入图片说明

I tried many other common ways to import the three.js that didn't work either!

我尝试了许多其他常用方法来导入三个.js,但也不起作用!

I'm no Vue expert at all, but three.js contains the following code block with exports, I think this may affect the way I need to import this library to avoid the compiling warnings.

我根本不是 Vue 专家,但是three.js 包含以下带有导出的代码块,我认为这可能会影响我需要导入这个库以避免编译警告的方式。

exports.WebGLRenderTargetCube = WebGLRenderTargetCube;
exports.WebGLRenderTarget = WebGLRenderTarget;
exports.WebGLRenderer = WebGLRenderer;
exports.ShaderLib = ShaderLib;
exports.UniformsLib = UniformsLib;
exports.UniformsUtils = UniformsUtils;
exports.ShaderChunk = ShaderChunk;
exports.FogExp2 = FogExp2;
exports.Fog = Fog;
exports.Scene = Scene;
(and so one...)



The complete Vue component filethat I'm using for my project.

我用于我的项目的完整 Vue 组件文件

采纳答案by posit labs

You can use a require statement like this:

您可以使用这样的 require 语句:

const THREE = require('THREE')

But some plugins assume THREEis available on window, so you may want to do window.THREE = require('THREE')

但是一些插件假设THREE在窗口上可用,所以你可能想要做window.THREE = require('THREE')

I don't have much experience with import statements, but the above should work.

我对导入语句没有太多经验,但以上应该有效。

回答by PolygonParrot

For anyone who just want to try out a basic setup. This is the three.js example in a vue component 'ThreeTest'. Project setup with vue-cli 'vue init webpack ProjectName', 'cd ProjectName', 'npm install three --save' and replace the 'HelloWorld' component with this one:

对于任何只想尝试基本设置的人。这是 vue 组件“ThreeTest”中的three.js 示例。使用 vue-cli 'vue init webpack ProjectName', 'cd ProjectName', 'npm install 三 --save' 进行项目设置,并用以下组件替换 'HelloWorld' 组件:

<template>
    <div id="container"></div>
</template>

<script>
import * as Three from 'three'

export default {
  name: 'ThreeTest',
  data() {
    return {
      camera: null,
      scene: null,
      renderer: null,
      mesh: null
    }
  },
  methods: {
    init: function() {
        let container = document.getElementById('container');

        this.camera = new Three.PerspectiveCamera(70, container.clientWidth/container.clientHeight, 0.01, 10);
        this.camera.position.z = 1;

        this.scene = new Three.Scene();

        let geometry = new Three.BoxGeometry(0.2, 0.2, 0.2);
        let material = new Three.MeshNormalMaterial();

        this.mesh = new Three.Mesh(geometry, material);
        this.scene.add(this.mesh);

        this.renderer = new Three.WebGLRenderer({antialias: true});
        this.renderer.setSize(container.clientWidth, container.clientHeight);
        container.appendChild(this.renderer.domElement);

    },
    animate: function() {
        requestAnimationFrame(this.animate);
        this.mesh.rotation.x += 0.01;
        this.mesh.rotation.y += 0.02;
        this.renderer.render(this.scene, this.camera);
    }
  },
  mounted() {
      this.init();
      this.animate();
  }
}
</script>

<style scoped>
    //TODO give your container a size.
</style>

回答by Leopold Kristjansson

Since the given answers were not working for me, I'll share the initial setup that worked for me. I am using Nuxt.js in my example.

由于给出的答案对我不起作用,我将分享对我有用的初始设置。我在我的例子中使用 Nuxt.js。

If this works, a green rotating cube should appear.

如果这有效,应该会出现一个绿色的旋转立方体。

enter image description here

在此处输入图片说明

<template>
  <div id="container"></div>
</template>
<script>
import * as THREE from 'three'

export default {
  name: 'ThreeTest',
  data() {
    return {
      cube: null,
      renderer: null,
      scene: null,
      camera: null
    }
  },
  methods: {
    init: function() {
      this.scene = new THREE.Scene()
      this.camera = new THREE.PerspectiveCamera(
        75,
        window.innerWidth / window.innerHeight,
        0.1,
        1000
      )

      this.renderer = new THREE.WebGLRenderer()
      this.renderer.setSize(window.innerWidth, window.innerHeight)
      document.body.appendChild(this.renderer.domElement)

      const geometry = new THREE.BoxGeometry(1, 1, 1)
      const material = new THREE.MeshBasicMaterial({ color: 0x00ff00 })
      this.cube = new THREE.Mesh(geometry, material)
      this.scene.add(this.cube)

      this.camera.position.z = 5

      const animate = function() {}
    },
    animate: function() {
      requestAnimationFrame(this.animate)

      this.cube.rotation.x += 0.01
      this.cube.rotation.y += 0.01

      this.renderer.render(this.scene, this.camera)
    }
  },
  mounted() {
    this.init()
    this.animate()
  }
}
</script>

回答by L3w1s

This is a follow up of the previous answer given by @PolygonParrot. As the limitation of comment length I had to put my answer here.

这是@PolygonParrot 给出的先前答案的后续。由于评论长度的限制,我不得不把我的答案放在这里。

Thanks very much for your answer, @PolygonParrot. It helped me a lot! Based on your demo code I figured out that the key to separate animation code from Vue component code is to pass a correct animation context to the module defined in animation.js. I think my first try failed maybe because of the "closure" feature of functional programming, which is a painful concept to adapt to for an ancient programmer like me. My animation.jsnow looks like this:

非常感谢您的回答,@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;
};

And the .vue file now looks like:

.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\>

As my scene grows bigger by adding more stuff in, my vue template can keep clean and hide animation logic behind the view. I think my use of context here still looks weird but at least it serve my purpose well just for now. render result

随着我的场景通过添加更多的东西变得更大,我的 vue 模板可以保持干净并隐藏视图后面的动画逻辑。我认为我在这里使用的上下文看起来仍然很奇怪,但至少现在它很好地满足了我的目的。 渲染结果

回答by eat mangos

Thank you Polygon Parrot for your template, It's what i came here looking for. Id like to include the window resize method specific for your example, just to make your template a little more complete.

谢谢 Polygon Parrot 的模板,这就是我来这里寻找的。我想包含特定于您的示例的窗口调整大小方法,只是为了使您的模板更完整一些。

methods:{ ...
onWindowResize(){
        this.renderer.setSize(window.innerWidth, window.innerHeight);
        this.camera.aspect = window.innerWidth / window.innerHeight;
        this.camera.updateProjectionMatrix()
    }
created(){
        window.addEventListener('resize', () => {this.onWindowResize()})
  }