1

我正在浏览 Angular 文档并看到以下代码片段。在我的脑海里,我想我记得document.getElementById()在 Angular 中使用是不受欢迎的,甚至ElementRefs不鼓励使用(以帮助防止 XSS 攻击)。如果确实不鼓励这些,那么为特定元素上的事件设置 Observable 的最佳实践是什么?

来自Angular Observables 文档

import { fromEvent } from 'rxjs';
import { ajax } from 'rxjs/ajax';
import { map, filter, debounceTime, distinctUntilChanged, switchMap } from 'rxjs/operators';

const searchBox = document.getElementById('search-box');  // <-- Is this OK?

const typeahead = fromEvent(searchBox, 'input').pipe(
  map((e: KeyboardEvent) => e.target.value),
  filter(text => text.length > 2),
  debounceTime(10),
  distinctUntilChanged(),
  switchMap(() => ajax('/api/endpoint'))
);
4

3 回答 3

3

在 Angular 中使用手动处理 DOM 是一种不好的方法。在 Angular 应用程序中,您应该始终使用 Angular 的方法来呈现页面。因为在大多数情况下,您将来需要为您的应用程序提供服务器端渲染,以使其对 Google 友好。但是后端的 Angular 的 SSR 引擎(Angular Universal)只模拟 XHR 对象,而不模拟 DOM 方法。

于 2019-09-23T10:45:13.243 回答
2

我建议使用角度ViewChild与模板中的组件进行交互。

ViewChild - 装饰器 API

配置视图查询的属性装饰器。更改检测器在视图 DOM 中查找与选择器匹配的第一个元素或指令。如果视图 DOM 发生变化,并且新的子元素与选择器匹配,则属性会更新。

例如:

import {Component, Directive, Input, ViewChild} from '@angular/core';

@Directive({selector: 'pane'})
export class Pane {
  @Input() id !: string;
}

@Component({
  selector: 'example-app',
  template: `
    <pane id="1" *ngIf="shouldShow"></pane>
    <pane id="2" *ngIf="!shouldShow"></pane>

    <button (click)="toggle()">Toggle</button>

    <div>Selected: {{selectedPane}}</div>
  `,
})
export class ViewChildComp {
  @ViewChild(Pane, {static: false})
  set pane(v: Pane) {
    setTimeout(() => { this.selectedPane = v.id; }, 0);
  }
  selectedPane: string = '';
  shouldShow = true;
  toggle() { this.shouldShow = !this.shouldShow; }
}

这是了解 Angular 中的 ViewChildren、ContentChildren 和 QueryList 的一个很好的示例

于 2019-09-23T07:27:25.603 回答
1

使用反应形式可能是更好的方法

//HTML:
<input #search [formControl]="search"/>

//Component
search=new FormControl('')
search.valueChanges.pipe(
  filter(text => text.length > 2),
  debounceTime(10),
  distinctUntilChanged(),
  switchMap(() => ajax('/api/endpoint'))
).subscribe();
于 2019-09-23T07:48:31.680 回答