【问题标题】:Import and use three.js library in vue componentvue组件中导入和使用three.js库
【发布时间】:2018-05-30 16:25:00
【问题描述】:

谁能解释一下我如何正确在 vue 组件中导入和使用 three.js 库?

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

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

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

我尝试了很多其他常见的方法来导入three.js,但也没有用!

我根本不是 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 file 用于我的项目。

【问题讨论】:

    标签: javascript import vue.js three.js shared-libraries


    【解决方案1】:

    适合任何只想尝试基本设置的人。这是 vue 组件“ThreeTest”中的 three.js 示例。使用 vue-cli 'vue 设置项目 init webpack ProjectName', 'cd ProjectName', 'npm install three --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>
    

    【讨论】:

    • 谢谢!正在寻找这样的东西,如果它有效,将尝试:)
    • 工作正常!需要进行一些调整以使其适用于不是正文唯一子级的组件,但建议将此作为对此代码的编辑。
    • IMO 这个答案应该是公认的。它更加详细和清晰。
    • 但是当我尝试将 initanimate 函数从 .vue 文件拆分到另一个 .js 文件时,为了让我的 vue 文件的脚本部分更加集中,我没有渲染任何内容屏幕。我可以从控制台日志中得知,我的 init()animate() 函数被三个.js 核心调用,并且我的动画函数从之前的 init 调用中得到了正确的初始化结果。我对 Vue 编程很陌生,所以任何能指出我的案例有什么问题的想法都会受到赞赏。
    • @L3w1s 因为我不知道你尝试了什么,所以我给你一个快速而肮脏的动画解决方案。该代码只能用于测试;)重要的是,您需要在动画的 init 函数中创建的上下文:animation.js let context; function set(c) { context = c; }; let animate = function animate() { requestAnimationFrame(animate); context.mesh.rotation.x += 0.01; context.mesh.rotation.y += 0.02; context.renderer.render(context.scene, context.camera); }; export { animate, set }; -> 下一条评论
    【解决方案2】:

    你可以像这样使用 require 语句:

    const THREE = require('THREE')
    

    但有些插件假定THREE 在窗口中可用,所以你可能想做window.THREE = require('THREE')

    我对 import 语句没有太多经验,但上面应该可以工作。

    【讨论】:

      【解决方案3】:

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

      如果可行,应该会出现一个绿色的旋转立方体。

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

      【讨论】:

        【解决方案4】:

        这是@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 模板可以保持干净并将动画逻辑隐藏在视图后面。我认为我在这里使用上下文看起来仍然很奇怪,但至少它现在很好地满足了我的目的。

        【讨论】:

          【解决方案5】:
          import * as THREE from "three";
          

          对我来说效果很好!

          【讨论】:

            【解决方案6】:

            感谢 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()})
              }
            

            【讨论】:

              猜你喜欢
              • 2021-03-25
              • 1970-01-01
              • 2017-06-04
              • 2016-05-26
              • 2018-08-26
              • 2018-01-16
              • 1970-01-01
              • 2019-11-01
              • 2020-08-30
              相关资源
              最近更新 更多