You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何用Signal Input替代Angular组件中的@Input() setter?

用Angular Signal重构双向搜索组件(移除@Input() setter)

重构后的完整组件代码

inpage-search.component.ts

import { ChangeDetectionStrategy, Component, effect, input, output, signal, toObservable } from '@angular/core';
import { FormsModule } from '@angular/forms';
import { ClarityModule } from '@clr/angular';
import { TranslateModule } from '@ngx-translate/core';
import { debounceTime, distinctUntilChanged } from 'rxjs';

@Component({
  selector: 'shared-inpage-search',
  standalone: true,
  imports: [FormsModule, TranslateModule, ClarityModule],
  templateUrl: './inpage-search.component.html',
  styleUrl: './inpage-search.component.css',
  changeDetection: ChangeDetectionStrategy.OnPush,
})
export class InpageSearchComponent {
  readonly placeholder = input<string>();
  readonly label = input<string>();

  // 外部传入的搜索词输入Signal(只读)
  readonly searchTermInput = input<string>('');
  // 内部维护的可写Signal,用于绑定输入框
  private readonly _searchTerm = signal<string>(this.searchTermInput());
  // 对外暴露的只读Signal(可选,供外部读取当前值)
  readonly searchTerm = this._searchTerm.asReadonly();

  readonly searchTermChange = output<string>();

  constructor() {
    // 监听外部输入变化,同步到内部状态
    effect(() => {
      const externalTerm = this.searchTermInput();
      if (externalTerm !== this._searchTerm()) {
        this._searchTerm.set(externalTerm);
        // 外部设置时直接触发输出,和原setter行为一致
        this.searchTermChange.emit(externalTerm);
      }
    });

    // 监听内部输入框变化,防抖后输出
    toObservable(this._searchTerm)
      .pipe(distinctUntilChanged(), debounceTime(200))
      .subscribe(term => {
        // 避免外部设置值时重复触发防抖输出
        if (term !== this.searchTermInput()) {
          this.searchTermChange.emit(term);
        }
      });
  }

  // 输入框值变化时更新内部Signal
  onSearchTermChange(searchTerm: string) {
    this._searchTerm.set(searchTerm);
  }
}

inpage-search.component.html

<clr-input-container>
  <label>{{ label() }}</label>
  <input
    clrInput
    class="search-term-input"
    [placeholder]="placeholder()"
    [ngModel]="searchTerm()"
    (ngModelChange)="onSearchTermChange($event)"
  />
</clr-input-container>

关键重构点说明

  1. 替换@Input() setter为输入Signal

    • 用input<string>('')创建只读的searchTermInput接收外部传入值,内部用可写Signal _searchTerm维护输入框状态(输入Signal本身不可修改)。
  2. 同步外部输入到内部状态

    • 通过effect监听外部输入Signal的变化,当值不一致时更新内部状态并触发输出,完全复刻原setter的行为。
  3. 用Signal替代Subject实现防抖

    • 借助toObservable()将内部Signal转换为Observable,配合RxJS操作符实现防抖去重,彻底移除原有的Subject,贴合Signal使用范式。
  4. 避免循环更新

    • 在防抖输出时判断当前值是否与外部输入一致,防止外部设置值后触发重复输出,避免不必要的循环更新。

组件使用示例

外部组件可通过双向绑定方式使用:

<shared-inpage-search
  [label]="'搜索'"
  [placeholder]="'输入关键词'"
  [searchTermInput]="externalSearchTerm()"
  (searchTermChange)="externalSearchTerm.set($event)"
></shared-inpage-search>

内容的提问来源于stack exchange,提问作者mandrag.ora

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.20 11:55:07