📜  如何在 AngularJS 中使用 fromEvent 方法创建 Observable 数据流?

📅  最后修改于: 2022-05-13 01:56:49.926000             🧑  作者: Mango

如何在 AngularJS 中使用 fromEvent 方法创建 Observable 数据流?

在本文中,我们将了解 Observable 如何在 Angular 应用程序中支持发布者和订阅者之间的数据共享。与 Promise 等技术相比,Observable 被称为事件处理、异步编程和处理多个值的更好技术。

  • Observable:表示可以随时间到达的数据流或数据源。但是如果没有订阅者,可观察对象是毫无意义的。

  • 订阅者:简单地说,它是一段监视 Observable 及其数据的代码。它获取数据并使其可用于组件。

必备知识:

  1. Angular v6.2.9 或更高版本和 RxJs v6.4.0 或更高版本
  2. 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 上显示这个流,我们将创建一个空的

    并继续将每本书添加为一个列表项,即在运行时将
  • 加入到
      中。

      准备工作:要从 DOM 元素触发的任何事件创建 observable,首先,我们需要获取对该 DOM 元素的引用。这可以使用 ViewChild 和 ElementRef 来完成。所以,这方面的代码可以写成:

      • HTML:
      • 打字稿:
        @ViewChild(‘addBtn’, {static: true}) addBtn: ElementRef;

        这里 this.addBtn.nativeElement 返回原生 DOM 元素。这将是我们的目标(准确地说是 EventTarget),它是 fromEvent 方法的第一个参数。第二个参数是“点击”,因为我们使用的是按钮点击。因此,代码变为:

        JavaScript:

        fromEvent(this.addBtn.nativeElement, 'click')
            .subscribe((res)=>{console.log(res)}

      一个小问题出现了!我们把这行代码放在哪里?

      嗯,最好的地方是 ngAfterViewInit。这是因为除非 ngOnInit 完成,否则 ViewChild 不会初始化 addBtn 元素。因此,我们将把这段代码放在 ngAfterViewInit 中,因为优先级 ngOnInit 是组件加载时要执行的第一个方法。

      JavaScript:

      ngAfterViewInit() {
        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

      我们可以在没有服务的情况下做到这一点,但要使我们的代码更加动态和有意义。让我们使用一个服务。这是正在做的。现在让我们进行必要的更改以使其正常工作。

      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 并添加了设施的方法。希望这可以帮助。