参照Angular公式文件以理解Angular:①

首先

我对React有了一定的理解,但因为工作需要理解Angular的代码,所以决定学习一下。Angular是JavaScript三大框架之一,希望能够在学习的过程中感受到与React的区别。我会参考官方文档来进行学习。

基本事项 (jī shì

首先,要理解Angular的基本概念。目前我們只通過閱讀Angular的官方文件,來了解Angular是什麼,如果有任何誤解,請務必糾正。

    • コンポーネント

 

    • アプリの構成要素。@Component() デコレータをつけた TypeScript クラス、HMTL テンプレート、スタイルが含まれる。カプセル化でき、直感的なアプリ構造にできる。

 

    • テンプレート

 

    • コンポーネントに必要となる HTML テンプレート。コンポーネントから動的な値を受け取り、状態変化に合わせて自動更新できる。値だけでなく、HTML や CSS、イベントもコンポーネントから渡すことができる。ディレクティブという機能もあるらしいが、これは現状正確には理解できていない。フラグによって表示を変えられる ngIf など、多数のディレクティブがあらかじめ用意されている。

 

    • 依存性の注入(DI; Dependency Injection)

 

    コンポーネントで使用したいサービスを注入できる。インスタンス化を明示的に行わなくてもサービスを扱えるため、簡単かつ柔軟にサービスをコンポーネント内で使用できる。

与 React 相比,组件的概述是相同的(尽管有函数组件和类组件的区别),但是在 React 中不存在指令或依赖注入这样的术语,所以对此的理解还很肤浅。(可能只是因为不知道而已,React 中也可能有。)
不仅仅通过阅读文档来理解,我们还将通过实际操作来深入理解。

Angular 教程

随着开始一个基本的Angular应用程序,我们将遵循一个修正和添加的方式,根据示例代码进行开发。我们还会进行与React的比较。

创建商品清单

1. *ngFor 指令

在下面的代码中,我们使用 *ngFor 指令来显示商品列表。

<h2>Products</h2>

<div *ngFor="let product of products">
  <h3>
    {{ product.name }}
  </h3>
</div>

产品是由products.ts文件中定义的数组,在product-list.component.ts中被导入并传递到product-list.component.html模板中。在编写的过程中,*ngFor可能类似于在React中使用的map函数。(以下是React代码示例,未经过执行确认)

{products.map((product, index) => {
  return (
    <div key={index}>
      <h3>{product.name}</h3>
    </div>
  )
})}

作为一个以 React 为基础的人,对于像

这样用””括起来的写法有点不太习惯。

2. 属性绑定

进一步在下面添加一个a标签,并使用属性绑定[]语法传递商品名作为title属性的值。据说可以将属性封装在[]中传递。确实,如果去除了[],将光标放在上面也看不到文字。

<h2>Products</h2>

<div *ngFor="let product of products">
  <h3>
    <a [title]="product.name + ' details'">
      {{ product.name }}
    </a>
  </h3>
</div>

条件判断指令 *ngIf

紧接着使用 *ngIf 指令。只有当 product 包含 description 时,才会显示 p 标签。

<h2>Products</h2>

<div *ngFor="let product of products">
  <h3>
    <a [title]="product.name + ' details'">
      {{ product.name }}
    </a>
  </h3>

  <p *ngIf="product.description">
    Description: {{ product.description }}
  </p>
</div>

这可能类似于 React 中的 && 和三元运算符。(以下是 React 代码示例,尚未验证运行)

{product.description && <p>Description: {product.description}</p>}

4. 事件绑定

最后,向按钮中添加 click 事件并将其绑定到 product-list.component.ts 的 share() 方法上。在事件绑定中,需要在事件周围使用 ( )。很容易混淆事件绑定的 ( ) 和属性绑定的 [ ]。

<h2>Products</h2>

<div *ngFor="let product of products">
  <h3>
    <a [title]="product.name + ' details'">
      {{ product.name }}
    </a>
  </h3>

  <p *ngIf="product.description">
    Description: {{ product.description }}
  </p>

  <button (click)="share()">
    Share
  </button>
</div>

目前,我覺得使用React的JSX(TSX)更容易。Angular明確地將HTML文件和TS文件分開,因此在小規模開發中,來回切換文件可能會感到繁瑣,但隨著規模的擴大,每個文件的角色變得明確,可讀性提高且修改也更容易。

将数据传递给子组件

1. 创建子组件

在这里,我们创建了一个作为子组件的 ProductAlertsComponent,并从父组件 ProductListComponent 中接收数据。在组件创建时,代码如下所示。(由于本文章中不需要 constructor 和 ngOnInit,因此以下部分将被省略。)

import { Component, OnInit } from '@angular/core';

@Component({
  selector: 'app-product-alerts',
  templateUrl: './product-alerts.component.html',
  styleUrls: ['./product-alerts.component.css']
})
export class ProductAlertsComponent implements OnInit {
  constructor() { }

  ngOnInit() {
  }

}

@Component() 装饰器用于标识定义的类为组件,并指定组件的选择器、模板、样式等相关元数据。

输入装饰器

为了从父组件接收商品数据,首先需要从 @angular/core 导入 Input ,然后在名为 product 的属性上使用 @Input() 装饰器进行定义。在这里,使用 ! 表示 product 是非空的。

import { Component, OnInit } from '@angular/core';
import { Input } from '@angular/core';
import { Product } from '../products';

@Component({
  selector: 'app-product-alerts',
  templateUrl: './product-alerts.component.html',
  styleUrls: ['./product-alerts.component.css']
})
export class ProductAlertsComponent {
  @Input() product!: Product;
}

通过上述方法,可以从父组件ProductListComponent接收属性的值。为了利用从父组件接收到的数据,我们可以在product-alerts.component.html中创建一个当价格超过$700时才会显示的Notify Me按钮。

<p *ngIf="product && product.price > 700">
  <button>Notify Me</button>
</p>

3. 在模块中声明

只需一种选项:
在 product-list.component.html 中添加选择器 ,就可以应用了。然而,在预览中出现了以下错误。

product-list-error.png

虽然在官方文件中没有写明,但似乎需要在 app.module.ts 文件中导入和在 declarations 中声明才能应用新创建的组件。经过补充后,成功应用并显示了售价超过700美元的Phone XL的“通知我”按钮。

app-module.png

将数据传递给父组件

1. @输出装饰器

为了使子组件的“Notify Me”按钮起作用,子组件需要通知父组件被点击的事件,并且父组件需要对该事件作出响应。为此,在子组件ProductAlertsComponent的product-alerts.component.ts文件中,我们从@angular/core中导入Output和EventEmitter,并使用@Output()装饰器和EventEmitter()的实例来定义名为notify的属性。通过这个设定,当notify属性的值被改变时,我们可以触发事件。

import { Component, OnInit } from '@angular/core';
import { Input } from '@angular/core';
import { Output, EventEmitter } from '@angular/core';
import { Product } from '../products';

@Component({
  selector: 'app-product-alerts',
  templateUrl: './product-alerts.component.html',
  styleUrls: ['./product-alerts.component.css']
})
export class ProductAlertsComponent {
  @Input() product!: Product;
  @Output() notify = new EventEmitter();
}

2. 在子组件中触发事件

通过使用事件绑定修复代码,以便在按下“Notify Me”按钮时触发事件。

<p *ngIf="product && product.price > 700">
  <button (click)="notify.emit()">Notify Me</button>
</p>

EventEmitter 的实例 notify 通过 emit() 方法发出事件。这个方法可以触发事件并将数据传递给父组件。(在这个例子中,emit() 方法没有参数,只是触发了事件而没有传递数据。在本文的最后,作为附加内容,也尝试了传递数据的情况。)

3. 在父组件中对事件进行响应。

当子组件ProductAlertsComponent触发事件时,在product-list.component.ts文件中将父组件ProductListComopnent的操作定义为onNotify()方法。

export class ProductListComponent {
  products = products;

  share() {
    window.alert('The product has been shared!');
  }

  onNotify() {
    window.alert('You will be notified when the product goes on sale');
  }
}

在product-list.component.html中,最后修改如下,从子组件接收数据。把product传递给子组件,并接收来自子组件的notify。

<h2>Products</h2>

<div *ngFor="let product of products">
  <h3>
    <a [title]="product.name + ' details'">
      {{ product.name }}
    </a>
  </h3>

  <p *ngIf="product.description">
    Description: {{ product.description }}
  </p>

  <button (click)="share()">
    Share
  </button>

  <app-product-alerts [product]="product" (notify)="onNotify()">
  </app-product-alerts>
</div>

4. (附赠品)EventEmitter()

虽然官方文件到这里就结束了,但不仅仅可以通过EventEmitter()触发事件,还可以同时传输数据。为了将产品名称作为通知内容更改并通知,我对Notify Me按钮做了以下三个修正。

    notify.emit() にて product.name を転送
<p *ngIf="product && product.price > 700">
  <button (click)="notify.emit(product.name)">Notify Me</button>
</p>
    onNitify() で name を引数にとり、アラートに表示
  ...
  onNotify(name: string) {
    window.alert(
      'Your will be notified when ' + name + ' product goes on sale'
    );
  }
}
    onNotify() メソッドに対して $event を渡す
  ...
  <app-product-alerts [product]="product" (notify)="onNotify($event)">
  </app-product-alerts>
</div>

更改後的结果如下。点击Phone XL的”通知我”按钮,确认能收到商品名称的通知。

EventEmitter.png

最后

我按照官方文档学习了Angular。与React相比,发现了许多不同之处,感到很有趣,同时也对其他功能很感兴趣,所以我打算继续学下去。在React中,我使用Hooks在所有函数组件中进行编写,所以我也想借此机会进一步深入理解关于类的概念(当然还有TypeScript)。

广告
将在 10 秒后关闭
bannerAds