Angular - 创建通用装饰器包装 @HostListener
Posted
技术标签:
【中文标题】Angular - 创建通用装饰器包装 @HostListener【英文标题】:Angular - Create common decorator wrapping @HostListener 【发布时间】:2020-05-12 12:01:57 【问题描述】:我正在尝试为我的一些使用 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
如果需要,我将为这些组件创建一个接口,以声明装饰器使用的公共服务和局部变量。
关于如何实现这种装饰器的任何想法、指导或帮助?
提前致谢。
【问题讨论】:
【参考方案1】:你可以使用自定义装饰器在没有@HostListner 的情况下实现它
online example
如何实现
-
创建一个函数来实现自定义装饰器 (
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)
【讨论】:
这对常春藤有效吗? github.com/angular/angular/issues/16023以上是关于Angular - 创建通用装饰器包装 @HostListener的主要内容,如果未能解决你的问题,请参考以下文章
typescript Angular 2应用程序角色访问装饰器,包装内置CanAccess功能。当用户角色不是ap时,防止视图转换