我有一个基于Angular2的客户端应用程序。 我有一个基类:
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
beforeUnloadHandler
在DerivedTwo
中工作正常,根本不会接到来电。
我知道很难找到为什么只是查看上面的信息,但也许有人可能怀疑可能导致这种奇怪行为的原因。
还有一些说明:
如果我使用以下内容:
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 {
}
它不起作用。
最后,如果我在@HostListener
和DerivedTwo
中使用DerivedOne
,它会有效,但我希望避免使用重复的代码。
希望上面的信息足以与之合作(至少要猜测一下)。
答案 0 :(得分:9)
更新2.3.0
您现在可以利用组件的对象继承。
您可以在此提交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
但仍然不清楚为什么@HostListener的解决方案不起作用 在第一位
具体来说,如果您在派生组件上有属性装饰器,那么它将无法工作。例如,我们说我们有以下代码:
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;
}
<强> Plunker 强>
它将转换为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(),
__metadata('design:type', Object)
], DerivedOne.prototype, "test", void 0);
DerivedOne = __decorate([
core_1.Component({
selector: 'derived-one',
template: '<h2>derived-one</h2>'
}),
__metadata('design:paramtypes', [])
], DerivedOne);
return DerivedOne;
}(BaseClass));
我们对以下几行感兴趣:
__decorate([
core_1.HostListener('window:beforeunload'),
__metadata('design:type', Function),
__metadata('design:paramtypes', []),
__metadata('design:returntype', void 0)
], BaseClass.prototype, "beforeUnloadHander", null);
...
__decorate([
core_1.Input(),
__metadata('design:type', Object)
], DerivedOne.prototype, "test", void 0);
HostListener
和Input
是属性修饰符(propMetadata
键)。这种方式将定义两个元数据条目 - 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}`);
})
}
}
<强> Plunker Example 强>
3)最后,如果你有如下所示的基类:
abstract class BaseClass {
beforeUnloadHander() {
console.log(`bla-bla from${this.constructor.name}`);
}
}
然后你必须使用正确的语法(你错过了 decorator属性中的括号:
host: {'(window:beforeunload)': 'beforeUnloadHander()' }
<强> Plunker Example 强>
希望它可以帮到你!