如何在Angular 2事件处理程序中访问"this"?

6
在我的组件的keydown事件处理程序中,我需要通过this修改组件的一个属性:
  canvasKeyHandler (event) {
    console.log('vrscene.canvasKeyHandler: event.keyCode=' + event.keyCode);
    console.log('vrscene.canvasKeyHandler: self.dolly' + this.dolly);

    CameraKeypressEvents.keyHandler(event, this.dolly) // <-- do something with this.dolly

但是this.dolly被设置为undefined

vrscene.canvasKeyHandler: self.dollyundefined

vrscene.html:

<div class="container" id ="canvas-container-2">
   <canvas id="vrruntime-view"
           class="camera-keypress-events"
           tabindex="1"
           (keydown)="canvasKeyHandler($event)"
           style="border: 1px solid black;"
           >
   </canvas>
           <!--camera-keypress-events [cubeScene]="cubeScene" -->

</div>

vrscene.ts:

import {Component} from 'angular2/core';
import {Injectable} from 'angular2/core';
import WebGLRenderer = THREE.WebGLRenderer;
import {VRRenderer} from '../vrrenderer/vrrenderer'
import {CameraKeypressEvents} from '../camera-keypress-events/camera-keypress-events'

import Object3D = THREE.Object3D;
import Scene = THREE.Scene;
import PerspectiveCamera = THREE.PerspectiveCamera;
import Mesh = THREE.Mesh;
import VRControls = THREE.VRControls;
import VREffect = THREE.VREffect;

@Component ({
  selector: 'vrscene',
  templateUrl: 'app//vrscene/vrscene.html',
})

@Injectable()
export class VRScene {

  private _scene: Scene;
  camera: PerspectiveCamera;
  dolly: Object3D;
  vrControls: VRControls;
  vrEffect: VREffect;
  webVrManager;
  sphere: Mesh;
  cube: Mesh;
  BaseRotation = new THREE.Quaternion();

  constructor() {}

  //initScene(width: number, height: number, renderer: VRRenderer) {
  init(width: number, height: number, vrRenderer: VRRenderer) {
    console.log('VRScene.init: entered')
    this.scene = new THREE.Scene;

    this.camera = new THREE.PerspectiveCamera(75, width / height);
    this.camera.position.set(0, 1.5, 100);
    this.dolly = new THREE.Object3D();
    this.dolly.position.z = 50;
    this.scene.add(this.dolly);
    //
    this.dolly.add(this.camera);

    this.vrControls = new THREE.VRControls(this.camera);

    this.vrEffect = new THREE.VREffect(vrRenderer.renderer);
    this.vrEffect.setSize(width, height);
    this.webVrManager = new (<any>window).WebVRManager(vrRenderer.renderer, this.vrEffect);
    console.log('VRScene.init: this.webVrManager=' + this.webVrManager);
    this.camera.quaternion.copy(this.BaseRotation);

    var geometry = new THREE.BoxGeometry(25, 25, 25);
    var meshParms = new Object();

    meshParms['color'] = 0xff8000;

    var material = new THREE.MeshBasicMaterial(meshParms);
    //material = new THREE.MeshBasicMaterial( {color: 0xffff00, side: THREE.DoubleSide} );
    this.cube = new THREE.Mesh(geometry, material);
    this.scene.add(this.cube);

    // draw!
    vrRenderer.canvas.focus();
    //CubeOnPlaneScene.prototype.mainLoop.bind(this)
    // bind the 'this' of the canvasKeyHandler to the definition-time 'this'
    //VRScene.prototype.canvasKeyHandler.bind(this)
  }

  canvasKeyHandler (event, dolly) {
    console.log('vrscene.canvasKeyHandler: event.keyCode=' + event.keyCode);
    //console.log('vrscene.canvasKeyHandler: this.dolly' + this.dolly);
    //console.log('vrscene.

canvasKeyHandler: self.dolly' + this.dolly);
    console.log('vrscene.canvasKeyHandler: dolly' + dolly);

    //CameraKeypressEvents.keyHandler(event, this.dolly)
    //CameraKeypressEvents.keyHandler(event, VRScene.prototype.canvasKeyHandler)
    CameraKeypressEvents.keyHandler(event, dolly)
  }

  doIt() : string {
    return 'hello from VRScene'
  }

  // getters  and setters
  get scene():Scene {
     return this._scene;
  }

  set scene(scene: Scene) {
    if (scene === undefined) throw 'Please supply a scene';
    this._scene = scene;
  }

}

按键处理程序:

import {Directive} from 'angular2/core';
import {CubeScene} from '../cube-scene/cube-scene';
import Object3D = THREE.Object3D;
import Vector3 = THREE.Vector3;
import {Base} from '../base/base';
import Quaternion = THREE.Quaternion;


@Directive({
  selector: '[camera-keypress-events]',
  providers: [],
  //host: {},
  host: {
    '(keypress)' : 'onKeypress($event)'
  },

})

export class CameraKeypressEvents {

  constructor() {}

  static CAMERA_MOVE_DELTA = 1.2;
  static CAMERA_ROT_DELTA = 5;

  static keyHandler (event, dolly: Object3D) {
    console.log('CameraKeypressEvents.keyHandler: event.keyCode=' + event.keyCode)
    console.log('CameraKeypressEvents.keyHandler: dolly=' + dolly)   
        switch( event.keyCode) {
      case 'S'.charCodeAt(0):
        console.log('you pressed s');
        //dolly.position.z += CAMERA_MOVE_DELTA;
        dolly.translateZ(this.CAMERA_MOVE_DELTA);
        console.log('dolly.postion.x=' + dolly.position.x);
      break;

      case 'W'.charCodeAt(0):
        //console.log('you pressed s');
        //this.dolly.position.z -= this.CAMERA_MOVE_DELTA;
        dolly.translateZ(-this.CAMERA_MOVE_DELTA);
        //console.log('this.do-ly.postion.x=' + this.dolly.position.x);
      break;

      case 'A'.charCodeAt(0):
        //this.dolly.position.x -= this.CAMERA_MOVE_DELTA;
        dolly.translateX(-this.CAMERA_MOVE_DELTA);
      break;

      case 'D'.charCodeAt(0):
        //console.log('you pressed s');
        //this.dolly.position.x += this.CAMERA_MOVE_DELTA;
        dolly.translateX(this.CAMERA_MOVE_DELTA);
        //console.log('this.dolly.postion.x=' + this.dolly.position.x);
      break;

      case 'N'.charCodeAt(0):
        //this.dolly.position.y -= this.CAMERA_MOVE_DELTA;
        dolly.translateY(-this.CAMERA_MOVE_DELTA);
      break;

      case 'P'.charCodeAt(0):
        //console.log('you pressed s');
        //this.dolly.position.y += this.CAMERA_MOVE_DELTA;
        //console.log('this.dolly.postion.x=' + this.dolly.position.x);
        dolly.translateY(this.CAMERA_MOVE_DELTA);
      break;

      case 'Q'.charCodeAt(0):
        var tmpQuat = (new THREE.Quaternion()).setFromAxisAngle( new THREE.Vector3(0,1,0), Base.ONE_DEG * this.CAMERA_ROT_DELTA);
        dolly.quaternion.multiply(tmpQuat);
      break;

      case 'E'.charCodeAt(0):
        var tmpQuat = (new THREE.Quaternion()).setFromAxisAngle( new THREE.Vector3(0,1,0), Base.ONE_DEG * -this.CAMERA_ROT_DELTA);
        dolly.quaternion.multiply(tmpQuat);
      break;
    };
  }

   onKeypress (event, cubeScene) {
    console.log('CameraKeypressEvents.onKeypress: event.keyCode=' + event.keyCode)
        //event.preventDefault();
    console.log('vtClass.canvasKeyhandler: cubeScene=' + cubeScene);
    console.log(event, event.keyCode, event.keyIdentifier);

    /*
    */
  }
}

我应该怎么做才能:

A)在keyhandler调用中传递实例?

我尝试过:

(keydown)="canvasKeyHandler($event,{{dolly}})"

B) 将canvasKeyHandler方法绑定到编译时的this

我尝试过:

// bind the callback 'this' of the canvasKeyHandler to the definition-time 'this'
VRScene.prototype.canvasKeyHandler.bind(this)

并且

  canvasKeyHandler (event) {
    ...
}.bind(this)

非常抱歉,如果这是一个显而易见的问题,但我正在学习Angular 2框架,并且在这一点上有些不知所措。我是否需要使用@Input?

非常感谢。


你能提供你组件的完整代码吗?谢谢! - Thierry Templier
好的,我已经通过了所有组件代码。如果你需要查看整个项目代码,那么我可能需要在Plunker上进行演示。 - vt5491
1
从您的VRScene组件中删除@Injectable()@Injectable仅在具有依赖关系的服务中需要)。在StackOverflow上发布“代码墙”通常会对您不利。人们通常不会花时间阅读它,无论是那些可以帮助您的人,还是未来遇到类似问题的读者。创建一个最小化的plunker,只显示出问题所在。例如,删除所有这些case语句 - 只显示一个,如果真的需要来演示问题。也许对您来说,将所有内容粘贴可能更容易,但正如我所说,您将得到较少的帮助。 - Mark Rajcok
去掉@Injectable并没有帮助。实际上,官方文档建议您为每个服务添加@Injectable,即使这些服务没有依赖关系。感谢您对包含最佳代码量的反馈。事实证明,这个特定的问题需要一个完整的plunker才能解决,因为问题有点微妙。 - vt5491
3个回答

2
(keydown)="canvasKeyHandler($event,{{dolly}})"

应该是

(keydown)="canvasKeyHandler($event,dolly)"

我不确定这是否真正解决了你的问题(我不太理解问题是什么)。

不行,事件处理程序中仍然显示dolly未定义。 - vt5491
1
我无法理解你的代码片段。例如,它们如何连接在一起?创建一个演示问题的 Plunker 怎么样? - Günter Zöchbauer
1
这与这个普通的JavaScript问题类似(https://dev59.com/1lzUa4cB1Zd3GeqPzAij),但是在Angular 2的上下文中。 - vt5491

1

this 对应于事件处理程序 (canvasKeyHandler) 中组件的实例。我认为使用以下内容来配置 keydown 事件的处理程序已经足够了:

(keydown)="canvasKeyHandler($event)"

我看到你在init方法中初始化了dolly属性。但是我没有看到这个方法被调用过。也许这就是你遇到问题的原因...

是的,我认为你在这方面走对了。然而,有一件事我没有提到(因为我认为它不相关..呃),就是我的组件处于继承关系中。我目前正在试图描述这种情况,但显然,Angular 2事件处理程序返回的this与预期的this不同,例如某些属性存在,而其他属性不存在,父/子信息取决于上下文等等。但是你的建议很有帮助,因为它让我相信这个处理程序应该可以工作,并集中精力解决问题所在。 - vt5491

0

这对我来说是一个关于DI微妙之处的真实案例。

基本上,这个问题可以归因于用户错误。Angular2或TypeScript没有正常工作的问题并不明显。我的主要问题是使用“init”方法来初始化组件,而不是在构造函数中进行初始化。我这样做是因为我想要延迟绑定属性,因为我觉得可能直到运行时才知道。这很好,但似乎注入器没有驱动我的init代码(或者可能是在那个时候属性还没有被定义)。还有一个因素是,有一个组件是通过继承而不是依赖注入来子类化父组件。看起来注入器可能只驱动了父类的构造函数而不是子类的构造函数,尽管我不能确定这是否是事实,因为我有几个问题同时出现。

我正在重构我的代码,只使用DI,并将所有初始化放在构造函数中,并且总体上更加严格地控制DI过程。

任何遇到类似问题的人,最重要的是要认识到组件可能存在或被创建的三个潜在上下文:编译时、注入时和运行时。甚至可能还有“加载时间”,但我假设这与“注入时间”相同。通常情况下,它们都是相同的,您不必区分它们,但请记住,如果您正在进行“后期动态初始化”,并且/或者使用继承而不是 DI,则注入的组件可能不会处于您期望的状态。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接