如何在 AngularJS 中使用 fromEvent 方法创建 Observable 数据流?
在本文中,我们将了解 Observable 如何在 Angular 应用程序中支持发布者和订阅者之间的数据共享。与 Promise 等技术相比,Observable 被称为事件处理、异步编程和处理多个值的更好技术。
Observable:表示可以随时间到达的数据流或数据源。但是如果没有订阅者,可观察对象是毫无意义的。
订阅者:简单地说,它是一段监视 Observable 及其数据的代码。它获取数据并使其可用于组件。
必备知识:
- Angular v6.2.9 或更高版本和 RxJs v6.4.0 或更高版本
- Node v10.15.3 或更高版本和 NPM v6.4.1 或更高版本
(注:RxJs 会自动安装 Angular,NPM 也会自动安装 Node)
你一定已经了解了 Angular 中 Observable 和 Subscribe 的基本概念。如果没有,请按照文章如何在 Angular 应用程序中实现 Observable-Subscribe。
项目结构:看起来像这样
创建 Observable 最常见和最简单的方法:创建 Observable最常见和最简单的方法是使用 RxJs 库提供的方法。它是一个 3rd 方库,在您创建新的 Angular 项目时会自动安装。一种这样的方法是fromEvent 。稍后我们将讨论其他方法,例如 Interval 和 Timer。
FromEvent: FromEvent 是 RxJs 提供的用于创建 Observable 的方法。最好的事情是我们可以直接从 DOM 事件创建 Observable。 DOM事件,就是点击事件、按键事件、滚动事件等,就是一个简单的鼠标点击,我们就可以创建一个数据流,也就是一个Observable。 FromEvent 将帮助我们解决这个问题。
句法:
fromEvent(target,eventName)
.subscribe((res)=>{console.log(res)})
我们来谈谈这两个参数。
target :它可以是任何 DOM EventTarget,例如按钮、单选按钮、滑块等。无论我们使用什么 DOM EventTarget,它都应该有注册/注销事件处理程序的方法。我们上面讨论的元素是内置机制。我们不必为此编写代码。
eventName :这是我们要监听的事件类型。
示例:单击、mousedown、mouseup、click、dblclick、mousemove、mouseover、mousewheel、mouseout、touchstart、touchmove、touchend、touchcancel、keydown、keypress、keyup 等。
方法:我们将在 UI 上创建一个简单的按钮“添加图书”,每次单击此按钮,我们将创建一个数据流。为简单起见,我们的数据流将只包含一个硬编码字符串,即“Book”。每次点击,我们都会继续生成书 1、书 2、书 3,等等。为了在 UI 上显示这个流,我们将创建一个空的
- 并继续将每本书添加为一个列表项,即在运行时将
- 加入到
- 中。
- HTML:
- 打字稿:
@ViewChild(‘addBtn’, {static: true}) addBtn: ElementRef;
这里 this.addBtn.nativeElement 返回原生 DOM 元素。这将是我们的目标(准确地说是 EventTarget),它是 fromEvent 方法的第一个参数。第二个参数是“点击”,因为我们使用的是按钮点击。因此,代码变为:
JavaScript:
fromEvent(this.addBtn.nativeElement, 'click') .subscribe((res)=>{console.log(res)}
第 1 步:创建一个新的 Angular 项目
ng new observable-app
第 2 步:创建一个名为 FromEventComponent 的组件
ng g c from-event
应创建 4 个新文件并更新 app.module.ts;
第三步:创建服务 PrintService
ng g s print-service
准备工作:要从 DOM 元素触发的任何事件创建 observable,首先,我们需要获取对该 DOM 元素的引用。这可以使用 ViewChild 和 ElementRef 来完成。所以,这方面的代码可以写成:
一个小问题出现了!我们把这行代码放在哪里?
嗯,最好的地方是 ngAfterViewInit。这是因为除非 ngOnInit 完成,否则 ViewChild 不会初始化 addBtn 元素。因此,我们将把这段代码放在 ngAfterViewInit 中,因为优先级 ngOnInit 是组件加载时要执行的第一个方法。
JavaScript:
ngAfterViewInit() { fromEvent(this.addBtn.nativeElement, 'click') .subscribe((res) => { console.log(res); }) }
如果我们单击该按钮,我们将在控制台上得到它:
让我们开始将其转换为工作代码。
我们可以在没有服务的情况下做到这一点,但要使我们的代码更加动态和有意义。让我们使用一个服务。这是正在做的。现在让我们进行必要的更改以使其正常工作。
from-event.component.html
print-service.service.ts
printStream(containerName, stream) { let element = document.createElement('li'); element.innerText = stream; document.getElementById(containerName).appendChild(element); }
from-event.component.ts
ngAfterViewInit() { let count = 1; fromEvent(this.addBtn.nativeElement, "click") .subscribe((res) => { this._printService.printStream( "elementContainer", "Book " + count++); }) }
from-event.component.html
from-event.component.ts
import { Component, ElementRef, OnInit, ViewChild } from "@angular/core"; import { fromEvent } from "rxjs"; import { PrintServiceService } from "../print-service.service"; @Component({ selector: "app-from-event", templateUrl: "./from-event.component.html", styleUrls: ["./from-event.component.css"], }) export class FromEventComponent implements OnInit { @ViewChild("addBtn", { static: true }) addBtn: ElementRef; constructor(private _printService: PrintServiceService) {} ngOnInit() {} ngAfterViewInit() { let count = 1; fromEvent(this.addBtn.nativeElement, "click").subscribe((res) => { this._printService.printStream("elementContainer", "Book " + count++); }); } }
print-service.service.ts
import { Injectable } from "@angular/core"; @Injectable({ providedIn: "root", }) export class PrintServiceService { constructor() {} printStream(containerName, stream) { // Creating li element in run time let element = document.createElement("li"); element.innerText = stream; // Appending li to ul document.getElementById(containerName).appendChild(element); } }
app.component.html
...
打印服务.service.ts
printStream(containerName, stream) { let element = document.createElement('li'); element.innerText = stream; document.getElementById(containerName).appendChild(element); }
因为我们创建了一个名为 printStream 的方法。它将接受两个参数。第一个参数是要附加数据的 DOM 元素,第二个参数是我要附加的数据或流。现在我们可以将此服务注入组件并使用此方法:
来自-event.component.ts
ngAfterViewInit() { let count = 1; fromEvent(this.addBtn.nativeElement, "click") .subscribe((res) => { this._printService.printStream( "elementContainer", "Book " + count++); }) }
我们采用了一个计数变量来区分流。它将继续使用“Book”添加自动递增的整数。在这里,在“this._printService.printStream('elementContainer', 'Book ' + count++)”这一行,我们告诉了要附加到哪里以及要附加什么。
最终代码:
来自-event.component.html
来自-event.component.ts
import { Component, ElementRef, OnInit, ViewChild } from "@angular/core"; import { fromEvent } from "rxjs"; import { PrintServiceService } from "../print-service.service"; @Component({ selector: "app-from-event", templateUrl: "./from-event.component.html", styleUrls: ["./from-event.component.css"], }) export class FromEventComponent implements OnInit { @ViewChild("addBtn", { static: true }) addBtn: ElementRef; constructor(private _printService: PrintServiceService) {} ngOnInit() {} ngAfterViewInit() { let count = 1; fromEvent(this.addBtn.nativeElement, "click").subscribe((res) => { this._printService.printStream("elementContainer", "Book " + count++); }); } }
打印服务.service.ts
import { Injectable } from "@angular/core"; @Injectable({ providedIn: "root", }) export class PrintServiceService { constructor() {} printStream(containerName, stream) { // Creating li element in run time let element = document.createElement("li"); element.innerText = stream; // Appending li to ul document.getElementById(containerName).appendChild(element); } }
app.component.html
...
输出:您可以看到每次单击鼠标都会处理流。在接下来的文章中,我们将了解 Interval 和 Timer。这只不过是另一种创建 Observable 并添加了设施的方法。希望这可以帮助。
- HTML: