angular - Angular - 创建通用装饰器包装 @HostListener
问题描述
我正在尝试找到一种方法来为我的一些使用 HostListener 的组件制作可重用的装饰器。
我目前拥有的几个功能(组件)非常相似,并且都具有相同的 @HostListener 块:
@Component({...})
export class MySearchComponent implements OnInit, OnDestroy {
@HostListener('window:scroll', [])
onScroll(): void {
this.loading = true;
this.commonService.getData(
this.tab,
this.query,
...
).subscribe(results => {
this.results = results;
this.loading = false;
})
}
}
HostListener 方法正在调用服务中的某个函数(从后端获取数据)并更新局部变量。将相同的服务注入所有组件,并且所有组件都可以使用相同的变量。事实上 - 逻辑是精确的并且在所有这些组件中重复。
我想做的是找到一种方法来创建一个自定义装饰器,该装饰器将包装重复的 HostListener,例如:
@Component({...})
@WithScrollHostListener()
export class MySearchComponent implements OnInit, OnDestroy {
}
如果需要,我将为这些组件创建一个接口,以声明装饰器使用的公共服务和局部变量。
关于如何实现这种装饰器的任何想法、指导或帮助?
提前致谢。
解决方案
您可以使用自定义装饰器在没有 @HostListner 的情况下实现它
如何实施
- 创建一个函数来实现自定义装饰器 (
WithScrollHostListener
)
function WithScrollHostListener() {
return function decorator(constructor) {
...
}
}
- 将自定义回调扩展到角钩(请参阅装饰器函数)
function WithScrollHostListener() {
// required
function extendHook(arg: {
hookName: string;
target: {
prototype;
};
fn: (hookArg: { componentInstance }) => void;
}) {
const original = arg.target.prototype[arg.hookName];
arg.target.prototype[arg.hookName] = function(...args) {
arg.fn({
componentInstance: this
});
original && original.apply(this, args);
};
}
// required
return function decorator(constructor) {
extendHook({
// hook's name according to you (e.x. ngOnInit , ngAfterViewInit)
hookName: "ngOnInit",
target: constructor,
// setup your custom logic
fn: hookArg => {
window.addEventListener("scroll", () =>
scrollFn({
commonComponent: hookArg.componentInstance
})
);
}
});
};
}
完整代码
import { Component, Injectable } from "@angular/core";
import { CommonService } from "./common.service";
// optional (shared the same structure with other component)
export interface CommonComponent {
loading?;
tab?;
query?;
results?;
commonService?: CommonService;
}
function WithScrollHostListener() {
// custom logic
function scrollFn(arg: { commonComponent: CommonComponent }) {
arg.commonComponent.loading = true;
arg.commonComponent.commonService
.getData(arg.commonComponent.tab, arg.commonComponent.query)
.subscribe(results => {
console.log(results);
arg.commonComponent.results = results;
arg.commonComponent.loading = false;
});
}
// required
function extendHook(arg: {
hookName: string;
target: {
prototype;
};
fn: (hookArg: { componentInstance }) => void;
}) {
const original = arg.target.prototype[arg.hookName];
arg.target.prototype[arg.hookName] = function(...args) {
arg.fn({
componentInstance: this
});
original && original.apply(this, args);
};
}
// required
return function decorator(constructor) {
extendHook({
// hook's name according to you (e.x. ngOnInit , ngAfterViewInit)
hookName: "ngOnInit",
target: constructor,
// setup your custom logic
fn: hookArg => {
window.addEventListener("scroll", () =>
scrollFn({
commonComponent: hookArg.componentInstance
})
);
}
});
};
}
@Component({
selector: "my-app",
templateUrl: "./app.component.html",
styleUrls: ["./app.component.css"]
})
@WithScrollHostListener()
export class AppComponent implements CommonComponent {
constructor(public commonService: CommonService) {
}
}
推荐阅读
- here-api - 突然无法加载 HERE 地图。甚至在他们的示例网站上也无法加载
- android - Retrofit 2 Xml Parse“参数'DASH'在类中没有匹配”
- android - FTS4 matchinfo 不适用于 android 房间数据库
- resilience4j - 带有 Spring mvc 的断路器注释(不是 Spring-boot)
- python - 使用 Python 和 xorg-server 监控计算机上花费的时间
- modelica - 试图模拟球和梁问题
- java - java线程中的while循环不运行
- html - 如何在离子中将列数均匀地划分为 2 行?
- machine-learning - Deeplabv3 不预测类
- r - R:计算具有子元素的嵌套列表中值的频率