Angular 7 ngZone 抛出未定义的错误
Angular 7 ngZone throwing undefined error
我正在尝试使用 three.js 渲染 3d 对象。但是,当我尝试初始化动画循环时(在 ngAfterViewInit
内),我不断收到以下错误:
TypeError: Cannot read property 'ngZone' of undefined
为了降低 cpu 成本,我使用 ngZone 在 Angular 之外触发 requestAnimationFrame
。即使我删除了 ngZone
的代码,我仍然会收到以下错误:
TypeError: Cannot read property 'animate' of undefined
这一切都发生在加载了适当的资源之后。
为避免混淆,ngZone
没有 class 作用域变量,只是在构造函数中将其作为参数调用。
代码:
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();
}
}
this.animate
在方法 loadResources
内部被调用。在这里你将它作为最后一个参数传递:
this.loadResources(this.modelValue, this.texture, this.scene, this.renderer, this.container, this.animate);
问题是 this.animate
将在 this.loader.load
的 callback
内部调用,而这个 callback
是一个常规函数,所以 this
在animate
不会有 ngZone
或 animate
。可能的解决方案是对 this.loader.load
的 callback
使用箭头函数(因为 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();
}
我正在尝试使用 three.js 渲染 3d 对象。但是,当我尝试初始化动画循环时(在 ngAfterViewInit
内),我不断收到以下错误:
TypeError: Cannot read property 'ngZone' of undefined
为了降低 cpu 成本,我使用 ngZone 在 Angular 之外触发 requestAnimationFrame
。即使我删除了 ngZone
的代码,我仍然会收到以下错误:
TypeError: Cannot read property 'animate' of undefined
这一切都发生在加载了适当的资源之后。
为避免混淆,ngZone
没有 class 作用域变量,只是在构造函数中将其作为参数调用。
代码:
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();
}
}
this.animate
在方法 loadResources
内部被调用。在这里你将它作为最后一个参数传递:
this.loadResources(this.modelValue, this.texture, this.scene, this.renderer, this.container, this.animate);
问题是 this.animate
将在 this.loader.load
的 callback
内部调用,而这个 callback
是一个常规函数,所以 this
在animate
不会有 ngZone
或 animate
。可能的解决方案是对 this.loader.load
的 callback
使用箭头函数(因为 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();
}