【问题标题】:Angular 7 ngZone throwing undefined errorAngular 7 ngZone 抛出未定义的错误
【发布时间】:2019-07-15 10:27:58
【问题描述】:

我正在尝试使用 three.js 渲染一个 3d 对象。但是,当我尝试初始化动画循环(在ngAfterViewInit 内)时,我不断收到以下错误:

TypeError: Cannot read property 'ngZone' of undefined

为了降低 CPU 开销,我使用 ngZone 在 Angular 之外触发 requestAnimationFrame。即使我删除了ngZone 的代码,我仍然收到以下错误:

TypeError: Cannot read property 'animate' of undefined

这一切都发生在加载适当的资源之后。 为避免混淆,ngZone 没有类范围变量,只是在构造函数中将其作为参数调用。

代码:

export class ProductComponent{
//setup variables
// shirt model and texutre are pulled from firebase storage
constructor(private storage : AngularFireStorage, public ngZone: NgZone) {

        this.modelUrl = this.storage.ref('path/to/model.obj').getDownloadURL();
        this.textureUrl = this.storage.ref('path/to/texture.jpg').getDownloadURL();

        this.camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 1, 2000);
        this.scene = new THREE.Scene();
        this.controls = new THREE.OrbitControls(this.camera,this.renderer.domElement);
        this.clock = new THREE.Clock();
        this.manager = new THREE.LoadingManager();
        this.loader = new THREE.OBJLoader(this.manager);
    }

ngAfterViewInit(){
    //setup
    this.loadResources(this.modelValue, this.texture, this.scene, this.renderer, this.container, this.animate);
 }
private loadResources(model, texture, scene, renderer, container, callback){

    this.camera.position.set(0, 0, 50);
    this.camera.lookAt(new THREE.Vector3(0, 0, 0));

    // scene

    scene.fog = new THREE.FogExp2(0xffffff, 0.0003);

    const ambientLight = new THREE.AmbientLight(0xcccccc, 0.4);
    scene.add(ambientLight);

    const pointLight = new THREE.PointLight(0xffffff, 0.8);
    this.camera.add(pointLight);
    scene.add(this.camera);

    this.loader.load(model, function (object) {
        object.traverse(function (child) {

            if (child instanceof THREE.Mesh) {

                child.material.map = texture;

                // repeat image on model
                child.material.map.wrapS = child.material.map.wrapT = THREE.RepeatWrapping;
                child.material.map.repeat.set(4, 4);

                child.material.needsUpdate = true;

            }

        });

        object.scale.set(1.5, 1, 1.5);
        scene.add(object);
        console.log('PARTS:', object.children);

        renderer.setPixelRatio(window.devicePixelRatio);
        renderer.setClearColor(scene.fog.color);
        renderer.setSize(window.innerWidth, window.innerHeight);
        container.appendChild(renderer.domElement);

        callback();
    }); //onProgress, onError
}

animate() : void {
        this.ngZone.runOutsideAngular(() => {
            requestAnimationFrame(this.animate);
        });
        this.render();
        this.update();

    }

}

【问题讨论】:

    标签: typescript ecmascript-6 three.js angular7 zone.js


    【解决方案1】:

    this.animate 在方法loadResources 内部被调用。在这里,您将它作为最后一个参数传递:

    this.loadResources(this.modelValue, this.texture, this.scene, this.renderer, this.container, this.animate);
    

    问题是this.animate 将在this.loader.loadcallback 内部被调用,而这个callback 是一个常规函数,所以animate 内部的this 不会有ngZone 或@987654331 @。可能的解决方案是对this.loader.loadcallback 使用箭头函数(因为在其中会调用this.animate):

    private loadResources(model, texture, scene, renderer, container, callback) {
    
      this.camera.position.set(0, 0, 50);
      this.camera.lookAt(new THREE.Vector3(0, 0, 0));
    
      // scene
      scene.fog = new THREE.FogExp2(0xffffff, 0.0003);
    
      const ambientLight = new THREE.AmbientLight(0xcccccc, 0.4);
      scene.add(ambientLight);
    
      const pointLight = new THREE.PointLight(0xffffff, 0.8);
      this.camera.add(pointLight);
      scene.add(this.camera);
    
      // use arrow function for callback of this.loader.load
      this.loader.load(model, (object) => {
    
        object.traverse(function (child) {
    
          if (child instanceof THREE.Mesh) {
    
            child.material.map = texture;
    
            // repeat image on model
            child.material.map.wrapS = child.material.map.wrapT = THREE.RepeatWrapping;
            child.material.map.repeat.set(4, 4);
    
            child.material.needsUpdate = true;
    
          }
        });
    
        object.scale.set(1.5, 1, 1.5);
        scene.add(object);
        console.log('PARTS:', object.children);
    
        renderer.setPixelRatio(window.devicePixelRatio);
        renderer.setClearColor(scene.fog.color);
        renderer.setSize(window.innerWidth, window.innerHeight);
        container.appendChild(renderer.domElement);
    
        // this.animate
        callback();
      }); //onProgress, onError
    }
    

    或者,如果您想使用常规函数作为this.loader.load 的回调,您可以将this 绑定到callback

    // assign this to const that,
    // so it can be used for binding
    const that = this;
    this.loader.load(model, function(object) {
    
      ...
    
      // this.animate
      const callbackWithThisBinding = callback.bind(that);
      callbackWithThisBinding();
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2019-04-18
      • 2019-07-20
      • 2014-07-09
      • 2014-05-30
      • 2018-11-15
      • 2018-07-19
      • 2014-09-21
      相关资源
      最近更新 更多