我有一个基类:
abstract class BaseClass { @HostListener('window:beforeunload') beforeUnloadHandler() { console.log('bla'); } }
和两个非常相似的派生类:
@Component({ selector: 'derived-one',templateUrl: './templates/app/+derived-one/derived-one.component.html' }) export class DerivedOne extends BaseClass { } @Component({ selector: 'derived-two',templateUrl: './templates/app/+derived-two/derived-two.component.html' }) export class DerivedTwo extends BaseClass { }
问题是,例如,在DerivedOne中,在DerivedTwo中,在UnloadHandler工作正常之前,它根本不接收调用.
我知道很难找到为什么只是查看上面的信息,但也许有人可能会怀疑可能导致这种奇怪行为的原因.
还有一些说明:
如果我使用以下内容:
abstract class BaseClass constructor(){ window.onbeforeunload = function(){ console.log('bla'); } } }
一切正常,但我仍然想找到一个基于Angular2的解决方案;
如果我写
abstract class BaseClass { beforeUnloadHandler() { console.log('bla'); } }
在derived-two.component.html中
<div (window.beforeunload)="beforeUnloadHandler()"></div>
一切都很好,但它看起来像一个丑陋的黑客;
如果我写的话
abstract class BaseClass { beforeUnloadHandler() { console.log('bla'); } }
和
@Component({ selector: 'derived-two',host: {'window:beforeunload': 'beforeUnloadHandler' } templateUrl: './templates/app/+derived-two/derived-two.component.html' }) export class DerivedTwo extends BaseClass { }
它不会起作用.
最后,如果我在DerivedTwo和DerivedOne中使用@HostListener,它可以工作,但我想避免使用重复的代码.
希望上面的信息足以与之合作(至少要有一些猜测).
您现在可以利用组件的对象继承.
您可以在此提交https://github.com/angular/angular/commit/f5c8e0989d85bc064f689fc3595207dfb29413f4中看到更多详细信息
旧版
1)如果你有一个班级:
abstract class BaseClass { @HostListener('window:beforeunload') beforeUnloadHander() { console.log('bla'); } }
然后它会工作
Plunker Example(在编辑器和监视控制台的某处放置空格)
但要小心,因为Angular2不支持完全继承 – Issue with binding and @ViewChild
But it still unclear why the solution with @HostListener didn’t work
in first place
特别是如果您在派生组件上有属性装饰器,它将无法工作.例如,假设我们有以下代码:
abstract class BaseClass { @HostListener('window:beforeunload') beforeUnloadHander() { console.log(`bla-bla from${this.constructor.name}`); } } @Component({ selector: 'derived-one',template: '<h2>derived-one</h2>' }) export class DerivedOne extends BaseClass { @Input() test; }
它将被转换为javascript,如:
var core_1 = require('@angular/core'); var BaseClass = (function () { function BaseClass() { } BaseClass.prototype.beforeUnloadHander = function () { console.log("bla-bla from" + this.constructor.name); }; __decorate([ core_1.HostListener('window:beforeunload'),__Metadata('design:type',Function),__Metadata('design:paramtypes',[]),__Metadata('design:returntype',void 0) ],BaseClass.prototype,"beforeUnloadHander",null); return BaseClass; }()); var DerivedOne = (function (_super) { __extends(DerivedOne,_super); function DerivedOne() { _super.apply(this,arguments); } __decorate([ core_1.Input(),Object) ],DerivedOne.prototype,"test",void 0); DerivedOne = __decorate([ core_1.Component({ selector: 'derived-one',template: '<h2>derived-one</h2>' }),[]) ],DerivedOne); return DerivedOne; }(BaseClass));
我们对以下几行感兴趣:
__decorate([ core_1.HostListener('window:beforeunload'),void 0) ],null); ... __decorate([ core_1.Input(),Object) ],void 0);
HostListener和Input是属性修饰符(propMetadata key).这种方式将定义两个元数据条目 – 在BaseClass和DerivedOne上
最后,当angular2从DerivedOne类中提取元数据时,它将只使用自己的元数据:
function InheritPropMetadata() { return (target: Function) => { const targetProps = Reflect.getMetadata('propMetadata',target); const parentTarget = Object.getPrototypeOf(target.prototype).constructor; const parentProps = Reflect.getMetadata('propMetadata',parentTarget); const mergedProps = Object.assign(targetProps,parentProps); Reflect.defineMetadata('propMetadata',mergedProps,target); }; }; @InheritPropMetadata() export class DerivedOne extends BaseClass {
这是一个有效的demo
2)如果你做了如下:
abstract class BaseClass constructor(){ window.onbeforeunload = function(){ console.log('bla'); }; } }
然后它将只调用一次因为你每次都覆盖window.onbeforeunload处理程序
您应该使用以下代码:
abstract class BaseClass { constructor(){ window.addEventListener('beforeunload',() =>{ console.log(`bla-bla from${this.constructor.name}`); }) } }
3)最后,如果您有基类,如下所示:
abstract class BaseClass { beforeUnloadHander() { console.log(`bla-bla from${this.constructor.name}`); } }
然后你必须使用正确的语法(你错过了
括号中的decorator属性:
host: {'(window:beforeunload)': 'beforeUnloadHander()' }
希望它能帮到你!