gpt4 book ai didi

html - 在 Angular 中执行函数之前如何等待最后一次击键?

转载 作者:行者123 更新时间:2023-12-05 08:30:23 25 4
gpt4 key购买 nike

我有以下输入:

 <input type="text" placeholder="Search for new results" (input)="constructNewGrid($event)" (keydown.backslash)="constructNewGrid($event)">

和函数

constructNewGrid(e){
// I want to wait 300ms after the last keystroke before constructing the new grid
// If the passed time is <300ms just return without doing something
// else start constructing new grid
}

我不太确定如何建立这样的条件。我应该如何处理这个问题?我在 RxJS 中阅读了关于 debounceTime 的内容,这正是我想要的,但我没有在函数中使用可观察对象,所以:你将如何在你的函数中构建这样的条件?

最佳答案

Observables 似乎是可行的方法,但是旧的 setTimeout 也会让您走得更远。出于美观原因,让我们首先重命名您的输入处理程序:

反斜杠事件看起来有点双重,因为这也触发了(input)

<input type="text" placeholder="Search for new results"
(input)="onInput(input.value)" #input>

在您的组件中,您有两种选择来处理此输入,使用或不使用可观察对象。让我先告诉你没有:

export class GridComponent {
private timeout?: number;

onInput(value: string): void {
window.clearTimeout(this.timeout);

this.timeout = window.setTimeout(() => this.constructNewGrid(value), 300);
}

constructNewGrid(value: string): void {
// expensive operations
}
}

这看起来很简单,对于您的用例来说可能就足够了。但是人们一直在谈论的那些很酷的 rxjs 流呢?嗯,看起来像这样:

export class GridComponent {
private search$ = new BehaviorSubject('');

private destroy$ = new Subject<void>();

ngOnInit(): void {
this.search$.pipe(
// debounce for 300ms
debounceTime(300),
// only emit if the value has actually changed
distinctUntilChanged(),
// unsubscribe when the provided observable emits (clean up)
takeUntil(this.destroy$)
).subscribe((search) => this.constructNewGrid(search));
}

ngOnDestroy(): void {
this.destroy$.next();
this.destroy$.complete();
}

onInput(value: string): void {
this.search$.next(value);
}

constructNewGrid(value: string): void {
// expensive operations
}
}

对于这样一个简单的东西,看起来需要更多的代码,事实确实如此。所以这取决于你。


但是如果您觉得这种模式是您要更频繁地使用的东西,您也可以考虑编写一个指令,如下所示:

@Directive({
selector: '[debounceInput]'
})
export class DebounceInputDirective {
@Input()
debounceTime: number = 0;

@HostListener('input', '[$event]')
onInput(event: UIEvent): void {
this.value$.next((event.target as HTMLInputElement).value);
}

private value$ = new Subject<string>();

@Output()
readonly debounceInput = this.value$.pipe(
debounce(() => timer(this.debounceTime || 0)),
distinctUntilChanged()
);
}

您可以像这样在您的组件中使用它:

<input type="text" placeholder="Search for new result"
(debounceInput)="onInput($event)" [debounceTime]="300">

以更 rxjs 风格编写此指令的另一种方法是:

@Directive({
selector: 'input[debounceInput]'
})
export class DebounceInputDirective {
@Input()
debounceTime: number = 0;

constructor(private el: ElementRef<HTMLInputElement>) {}

@Output()
readonly debounceInput = fromEvent(this.el.nativeElement, 'input').pipe(
debounce(() => timer(this.debounceTime)),
map(() => this.el.nativeElement.value),
distinctUntilChanged()
);
}

使用指令(和不相关的 async 管道)的好处是您不必担心挥之不去的 rxjs 订阅。这些可能是潜在的内存泄漏。


但是等等!还有更多。你可以忘记所有这些事情,回到 angular typescript 的根源。装饰师!在你的方法上使用一个花哨的去抖动装饰器怎么样。然后,您可以保留所有内容,只需在您的方法上方添加 @debounce(300) 即可:

@debounce(300)
constructNewGrid(event): void {
// ...
}

什么?真的吗?这个 debounce 装饰器是什么样子的。好吧,它可以像这样简单:

function debounce(debounceTime: number) {
let timeout: number;

return function (
_target: any,
_propertyKey: string,
descriptor: PropertyDescriptor
) {
const originalMethod: Function = descriptor.value;

descriptor.value = (...args: any[]) => {
window.clearTimeout(timeout);
timeout = window.setTimeout(() => originalMethod(...args), debounceTime);
};

return descriptor;
};
}

但这是未经测试的代码,但它可以让您了解所有可能的情况:)

关于html - 在 Angular 中执行函数之前如何等待最后一次击键?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/64604659/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com