规格示例_最佳角度示例

规格示例

Angular is a TypeScript-based open source framework used to develop frontend web applications. It is the successor of AngularJS and all mentions of Angular refer to versions 2 and up. Angular has features like generics, static-typing, and also some ES6 features.

Angular是用于开发前端Web应用程序的基于TypeScript的开源框架。 它是AngularJS的后继产品,对Angular的所有提及均指版本2及更高版本。 Angular具有泛型,静态类型化等功能,还有一些ES6功能。

版本记录 (Version History)

Google released the initial version of AngularJS on October 20, 2010. The stable release of AngularJS was on December 18, 2017, of version 1.6.8. The last significant release of AngularJS, version 1.7, took place on July 1, 2018, and is currently in a 3 year Long Term Support period. Angular 2.0 was first announced on September 22, 2014, at the ng-Europe conference. One new feature of Angular 2.0 is dynamic loading, and most of the core functionality was moved to modules.

Google于2010年10月20日发布了AngularJS的初始版本。AngularJS的稳定版本于2017年12月18日发布,版本为1.6.8。 AngularJS的最新重要版本1.7版于2018年7月1日发布,目前处于3年的长期支持期内。 Angular 2.0于2014年9月22日在ng-Europe会议上首次发布。 Angular 2.0的一项新功能是动态加载,并且大多数核心功能已移至模块中。

After some modifications, Angular 4.0 was released in December 2016. Angular 4 is backwards compatible with Angular 2.0, and some new features are the HttpClient library and new router life cycle events. Angular 5 released on November 1, 2017, a major feature of which is support for progressive web apps. Angular 6 was released in May 2018, and Angular 7 in October 2018. The latest stable version is 7.0.0.

经过一些修改,Angular 4.0于2016年12月发布。Angular4向后兼容Angular 2.0,并且一些新功能是HttpClient库和新的路由器生命周期事件。 Angular 5于2017年11月1日发布,其主要功能是支持渐进式Web应用程序。 Angular 6于2018年5月发布,Angular 7于2018年10月发布。最新的稳定版本是7.0.0

安装 (Installation)

The easiest way to install Angular is through Angular CLI. This tool allows the creation of new projects and generating components, services, modules, and so on, to a standard the Angular team consider to be best practices.

安装Angular的最简单方法是通过Angular CLI 。 该工具允许创建新项目并生成组件,服务,模块等,以符合Angular团队认为是最佳实践的标准。

Angular 2.x及更高版本 (Angular 2.x and Up)

安装Angular CLI (Install Angular CLI)
npm install -g @angular/cli
创建工作区和初始应用程序 (Create a Workspace and Initial Application)

You develop apps in the context of an Angular workspace. A workspace contains the files for one or more projects. A project is the set of files that comprise an app, a library, or end-to-end (e2e) tests.

您可以在Angular工作区的上下文中开发应用程序。 工作区包含一个或多个项目的文件。 项目是由应用程序,库或端到端(e2e)测试组成的文件集。

ng new my-app
服务应用 (Serve the Application)

Angular includes a server so that you can easily build and serve your app locally.

Angular包含一台服务器,因此您可以轻松地在本地构建和服务您的应用程序。

  1. Navigate to the workspace folder (my-app)

    导航到工作区文件夹( my-app )

Launch the server by using the CLI command ng serve with the --open option

通过使用带有--open选项的CLI命令ng serve启动服务器

cd my-app
ng serve --open

Hooray, you created your first angular app!!!

万岁,您创建了自己的第一个有角度的应用程序!

组件 (Components)

Angular contains many schematics for building applications. Components are one such schematic. They encompass a single unit of logic concerned with a single part of the application. Components often partner with other schematics to operate more effectively.

Angular包含许多用于构建应用程序的示意图 。 组件就是这样一种示意图。 它们包含与应用程序的单个部分有关的单个逻辑单元。 组件通常与其他原理图配合使用以更有效地运行。

Components simplify the application. Funneling logic into a single section of the visible interface is their primary goal. To build applications step-by-step, you must build component-by-component. Components act as Angular's building blocks after all.

组件简化了应用程序。 将逻辑集中到可见界面的单个部分是他们的主要目标。 要逐步构建应用程序,必须逐组件构建。 组件毕竟是Angular的基石。

组件类和元数据 (Component Class and Metadata)

The CLI command ng generate component [name-of-component] yields the following.

CLI命令ng generate component [name-of-component]产生以下内容。

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

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

  ngOnInit() { }
}

This is the basic skeleton from which all great components originate. The @Component decorator is the most important part. Without it, the above example becomes a generic class. Angular relies on decorators to discern a class' schematic type.

这是所有重要组成部分的基础骨架。 @Component装饰器是最重要的部分。 没有它,上面的示例将成为通用类。 Angular依靠装饰器来识别类的示意图类型。

@Component receives metadata as a single object. Decorators are just JavaScript functions under the hood. They take in arguments as with the metadata object. The metadata object configures a component's basic dependencies. Each fields plays a role.

@Component元数据作为单个对象接收。 装饰器只是底层JavaScript函数。 它们与元数据对象一样接受参数。 元数据对象配置组件的基本依赖关系。 每个字段都扮演一个角色。

  • selector: tells Angular to associate the component with a certain element in the application’s template HTML.

    selector:告诉Angular将组件与应用程序模板HTML中的某个元素相关联。

  • templateUrl: accepts the file location of the component’s template HTML (this is where data gets displayed to).

    templateUrl:接受组件模板HTML的文件位置(这是数据显示到的位置)。

  • styleUrls: accepts an array of style-sheet file locations (strings). These style-sheets target the component’s assigned template.

    styleUrls:接受样式表文件位置(字符串)的数组。 这些样式表以组件的分配模板为目标。

Think of metadata as a big blob of configuration. The decorator takes it so that it can generate the data specific to the component. The decorator decorates the underlying class with data necessary for its class' behavior. A component class that is.

将元数据视为一大堆配置。 装饰器接受它,以便它可以生成特定于组件的数据。 装饰器使用其类的行为所必需的数据来装饰基础类。 是一个组件类。

The class' signature exports by default so that the component can be imported. ngOnInit also gets implemented. implements tells the class to define certain methods per the interface's definition. ngOnInit is a lifecycle hook.

默认情况下,该类的签名会导出,以便可以导入组件。 ngOnInit也已实现。 implements告诉类根据接口的定义定义某些方法。 ngOnInit是生命周期挂钩。

组件数据 (Component Data)

Data drives everything. Components are no exception. Components encapsulate all their data. To receive data externally, a component must explicitly declare it. This form of privacy keeps information from clashing across the component tree.

数据驱动一切。 组件也不例外。 组件封装了所有数据。 要从外部接收数据,组件必须显式声明它。 这种隐私形式可防止信息在组件树之间冲突。

Data determines what gets displayed from the component class to its template. Any updates to the class’ data will (or at least should) update the template display.

数据确定从组件类显示到其模板的内容。 对类数据的任何更新将(或至少应)更新模板显示。

Components will often initialize a set of members (or variables) that store data. They are used throughout the component class logic for convenience. This information fuels the logic resulting in the template and its behavior. See the following example.

组件通常会初始化一组存储数据的成员(或变量)。 为了方便起见,在整个组件类逻辑中使用它们。 此信息助长了导致模板及其行为的逻辑。 请参见以下示例。

// ./components/example/example.component.ts

import { Component, OnInit } from '@angular/core';
import { Post, DATA } from '../../data/posts.data';

@Component({
  selector: 'app-example',
  templateUrl: './example.component.html'
})
export class ExampleComponent implements OnInit {
  username: string;
  totalPosts: number;
  allPosts: Post[];

  deletePost(index: number): void {
    this.allPosts.splice(index, 1);
    this.totalPosts = this.allPosts.length;
  }

  ngOnInit(): void {
    this.username = DATA.author;
    this.totalPosts = DATA.thePosts.length;
    this.allPosts = DATA.thePosts;
  }
}
<!-- ./components/example/example.component.html -->

<h1>{{ username }}</h1>
<span>Change Name: </span><input [(ngModel)]="username">
<h3>Posts: {{ totalPosts }}</h3>
<ul>
<hr/>
<div *ngFor="let post of allPosts; let i=index">
  <button (click)="deletePost(i)">DELETE</button>
  <h6>{{ post.title }}</h6>
  <p>{{ post.body }}</p>
  <hr/>
</div>
</ul>

Note the ways the component interacts with its data. It first fetches it from ../../data/posts.data before it begins to forward it to the template for display.

注意组件与其数据交互的方式。 它首先从../../data/posts.data获取数据,然后才开始将其转发到模板进行显示。

The data shows up throughout the template. Inside the double curly braces, a variable’s value is mapped from the component class into the braces. The *ngFor loops across the allPosts class array. Clicking on the button removes a specific element from allPosts by its index. You can even change the topmost username by typing into the input box.

数据显示在整个模板中。 在双花括号内,变量的值从组件类映射到花括号中。 *ngForallPosts类数组中循环。 单击该按钮可从allPosts按其索引删除特定元素。 您甚至可以通过在输入框中键入来更改最高username

The above interactions alter the component class' data which in turn updates the component's template HTML. Components provide the backbone logic that facilitates the flow of data. The template HTML makes that data readable to the user.

上述交互会更改组件类的数据,从而更新组件的模板HTML。 组件提供了促进数据流的主干逻辑。 模板HTML使该数据对用户可读。

数据绑定 (Data Binding)

Data often defines the look of an application. Interpreting that data into the user interface involves class logic (*.component.ts) and a template view (*.component.html) . Angular connects them through data binding. Think of data binding as a tool for component interaction.

数据通常定义应用程序的外观。 将数据解释为用户界面涉及类逻辑( *.component.ts )和模板视图( *.component.html )。 Angular通过数据绑定将它们连接起来。 可以将数据绑定视为组件交互的工具。

组件和模板 (Component and Template)

The component stores most of its logic and data inside of its class decorated with @Component. This decorator defines the class as a component with template HTML. The template of the component represents the class within the application. The focus here needs to be between the component's class and the template HTML.

该组件将其大多数逻辑和数据存储在用@Component装饰的@Component 。 该装饰器将类定义为带有模板HTML的组件。 组件的模板表示应用程序中的类。 这里的焦点需要在组件的类和模板HTML之间。

This is where data binding occurs. Element properties and events get assigned values. These values, defined by the component class, serve either one of two roles. One is to produce data that the template then receives. The other handles events emitted by the template element.

这是发生数据绑定的地方。 元素属性和事件获得分配的值。 由组件类定义的这些值充当两个角色之一。 一种是产生模板随后接收的数据。 另一个处理模板元素发出的事件。

元素属性 (Element Properties)

To recognize data-bound element properties, Angular uses a special bracket syntax.

为了识别数据绑定元素的属性,Angular使用特殊的括号语法。

// my.component.ts
@Component({
  templateUrl: './my.component.html'
})

export class MyComponent {
  value:type = /* some value of type */;
}
<!-- my.component.html -->
<any-element [property]=“value”>innerHTML</any-element>

Bear with me on this one.

忍受我这个。

[property] mirrors the property in the Domain Object Model (DOM) element's object node. Do not confuse object properties with a DOM element's attributes. Properties and attributes often share the same name and do the same thing. There is one clear distinction however.

[property]镜像域对象模型(DOM)元素的对象节点中的属性。 不要将对象属性与DOM元素的属性混淆。 属性和属性通常共享相同的名称并执行相同的操作。 但是,有一个明显的区别。

Remember that attr (attributes) is a single property of the underlying DOM object. It gets declared at the DOM’s instantiation with attribute values matching the element's definition. It maintains the same value after that. Properties each have their own key-value field in a DOM object node. These properties are mutable post-instantiation.

请记住, attr (属性)是基础DOM对象的单个属性。 它在DOM的实例中被声明为具有与元素定义匹配的属性值。 之后,它将保持相同的值。 每个属性在DOM对象节点中都有自己的键值字段。 这些特性在实例化后是可变的。

Know the difference between attributes and properties. It will lead to a better understanding of how Angular binds data to properties (property binding). Angular will hardly ever bind data to an element’s attributes. Exceptions to this are very rare. One last time: Angular binds component data to properties, not attributes!

了解属性和属性之间的区别。 它将使您更好地了解Angular如何将数据绑定到属性(属性绑定)。 Angular几乎不会将数据绑定到元素的属性。 很少有例外。 最后一次:Angular将组件数据绑定到属性,而不是属性!

Referring back to the example, the [ … ] in the element's property assignment have special meaning. The brackets show that property is bound to “value” on the right of the assignment.

再次参考示例,元素属性分配中的[ … ]具有特殊含义。 方括号显示property绑定到分配右侧的“value”

value also has special meaning within context of the brackets. value by itself is a string literal. Angular reads it and matches its value against component class members. Angular will substitute the value of the matching member attribute. This of course refers to the same component class that hosts the template HTML.

value在方括号内也有特殊含义。 value本身就是字符串文字。 Angular读取它,并将其值与组件类成员匹配。 Angular将替换匹配成员属性的值。 当然,这是指托管模板HTML的相同组件类。

The unidirectional flow of data from component to template is complete. The member matched against right assignment of the bracketed property provides the value. Note that changes to the member's value in the component class percolate down to the template. That is Angular's change detection at work. Changes within the template's scope have no effect on the component class member.

从组件到模板的单向数据流已完成。 与右括号属性匹配的成员提供value 。 请注意,在组件类中对成员值的更改会渗透到模板中。 那就是Angular在工作中的变更检测。 模板范围内的更改对组件类成员没有影响。

Key take-away: the component class provides the data while the template displays it.

关键要点:组件类在模板显示时提供数据。

I failed to mention that data values can also show up in a component’s innerHTML. This last example implements double curly braces. Angular recognizes these braces and interpolates the matching component class data into the innerHTML of the div.

我没有提到数据值也可以显示在组件的innerHTML 。 最后一个示例实现了双花括号。 Angular识别出这些花括号,并将匹配的组件类数据插入到divinnerHTML中。

<div>The value of the component class member ‘value’ is {{value}}.</div>

事件处理 (Event Handling)

If the component supplies data, then the template supplies events.

如果组件提供数据,则模板提供事件。

// my.component.ts
@Component({
  templateUrl: './my.component.html'
})

export class MyComponent {
  handler(event):void {
      // function does stuff
  }
}
// my.component.html
<any-element (event)=“handler($event)”>innerHTML</any-element>

This works similarly to property binding.

这类似于属性绑定。

The (event) pertains to any valid event type. For example, one of the most common event types is click. It emits when you click your mouse. Regardless of the type, event is bound to “handler” in the example. Event handlers are usually member functions of the component class.

(event)与任何有效的事件类型有关。 例如, click是最常见的事件类型之一。 当您单击鼠标时,它会发出。 在示例中,无论类型如何, event都绑定到“handler” 。 事件处理程序通常是组件类的成员函数。

The ( … ) are special to Angular. Parenthesis tell Angular an event is bounded to the right assignment of handler. The event itself originates from the host element.

( … )对于Angular是特殊的。 括号告诉Angular事件绑定到handler的正确分配。 事件本身起源于宿主元素。

When the event does emit, it passes the Event object in the form of $event. The handler maps to the identically named handler function of the component class. The unidirectional exchange from the event-bound element to the component class is complete.

当事件确实发出时,它将以$event的形式传递Event对象。 handler映射到组件类的同名handler函数。 从事件绑定元素到组件类的单向交换已完成。

Emitting events from the handler, while possible, do not impact the template element. The binding is unidirectional after all.

在可能的情况下,从处理程序中发出事件不会影响模板元素。 绑定毕竟是单向的。

指令 (Directives)

Directives are component elements and attributes created and recognized by Angular. Angular associates the element or attribute with its corresponding class definition. @Directive or @Component decorates these classes. Both are indicative to Angular that the class performs as a directive.

指令是Angular创建和识别的组成元素和属性。 Angular将元素或属性与其对应的类定义相关联。 @Directive@Component装饰这些类。 两者都指示Angular该类作为指令执行。

Some directives modify the style of the host element. Other directives display views or insert into existing ones as embedded views. On other words, they alter the HTML layout.

一些指令修改了host元素的样式。 其他指令显示视图或将其作为嵌入式视图插入到现有的视图中。 换句话说,它们会更改HTML布局。

In any case, directives signal the Angular compiler. They mark components for modification depending on the class logic of the directive.

在任何情况下,指令都会向Angular编译器发出信号。 它们根据指令的类逻辑标记要修改的组件。

结构指令 (Structural Directive)

Here are three examples of structural directives. Each one has a logical counterpart (if, for, and switch).

这是结构指令的三个示例。 每个对象都有一个逻辑对应对象( ifforswitch )。

  • *ngIf

    * ngIf
  • *ngFor

    * ngFor
  • *ngSwitchCase and *ngSwitchDefault

    * ngSwitchCase和* ngSwitchDefault

Important note: all three are available through the CommonModule import. It is available from @angular/common for importation within the application's root module.

重要说明:这三个都可以通过CommonModule导入获得。 它可以从@angular/common获取,以在应用程序的根模块中导入。

* ngIf (*ngIf)

*ngIf tests a given value to see if it is truthy or falsy based off general boolean evaluation in JavaScript. If truthy, the element and its innerHTML show up. Otherwise, they never render to the Domain Object Model (DOM).

*ngIf根据JavaScript中的常规布尔评估测试给定值,看它是还是 。 如果属实,则会显示该元素及其innerHTML。 否则,它们将永远不会呈现给域对象模型(DOM)。

<!-- renders “<h1>Hello!</h1>” -->
<div *ngIf="true">
  <h1>Hello!</h1>
</div>

<!-- does not render -->
<div *ngIf="false">
  <h1>Hi!</h1>
</div>

This is a contrived example. Any member value from the template's component class can be substituted in for true or false.

这是一个人为的例子。 模板的组件类中的任何成员值都可以用truefalse代替。

NOTE: You also can do following thing with *ngIf to get access to observalbe value

注意:您还可以使用* ngIf执行以下操作以获取observalbe值

<div *ngIf="observable$ | async as anyNameYouWant">
  {{  anyNameYouWant }}
</div>
* ngFor (*ngFor)

*ngFor loops based off a right-assigned, microsyntactic expression. Microsyntax moves beyond the scope of this article. Know that microsyntax is a short form of logical expression. It occurs as a single string capable of referencing class member values. It can loop iterable values which makes it useful for *ngFor.

*ngFor循环基于右分配的 *ngFor表达式。 Microsyntax超出了本文的范围。 知道微语法是逻辑表达的一种简短形式。 它作为能够引用类成员值的单个字符串出现。 它可以循环迭代值,这对于*ngFor很有用。

<ul>
  <li *ngFor=“let potato of [‘Russet’, ‘Sweet’, ‘Laura’]; let i=index”>
      Potato {{ i + 1 }}: {{ potato }}
  </li>
  <!-- Outputs
  <li>
      Potato 1: Russet
  </li>
  <li>
      Potato 2: Sweet
  </li>
  <li>
      Potato 3: Laura
  </li>
  -->
</ul>

[‘Russet’, ‘Sweet’, ‘Laura’] is an iterable value. Arrays are one of the most common iterables. The *ngFor spits out a new <li></li> per array element. Each array element is assigned the variable potato. This is all done utilizing microsyntax. The *ngFor defines the structural content of the ulelement. That is characteristic of a structural directive.

['Russet', 'Sweet', 'Laura']是一个可迭代的值。 数组是最常见的可迭代对象之一。 *ngFor为每个数组元素吐出一个新的<li></li> 。 每个数组元素都分配了变量potato 。 所有这些都是利用微语法完成的。 *ngFor定义ul元素的结构内容。 这是结构指令的特征。

NOTE: You can also do following thing with *ngFor directive to get access to observalbe value (hacky)

注意:您还可以使用* ngFor指令执行以下操作以获取对observalbe值的访问(hacky)

<div *ngFor="let anyNameYouWant of [(observable$ | async)]">
  {{  anyNameYouWant }}
</div>
* ngSwitchCase和* ngSwitchDefault (*ngSwitchCase and *ngSwitchDefault)

These two structural directives work together to provide switch functionality to template HTML.

这两个结构性指令共同作用,为模板HTML提供switch功能。

<div [ngSwitch]=“potato”>
  <h1 *ngSwitchCase=“‘Russet’”>{{ potato }} is a Russet Potato.</h1>
  <h1 *ngSwitchCase=“‘Sweet’”>{{ potato }} is a Sweet Potato.</h1>
  <h1 *ngSwitchCase=“‘Laura’”>{{ potato }} is a Laura Potato.</h1>
  <h1 *ngSwitchDefault>{{ potato }} is not a Russet, Sweet, nor Laura Potato.</h1>
</div>

Only one of the *ngSwitch… expressions renders. Notice the [ngSwitch] attribute inside of the divelement wrapping the switch. This passes the value of potato along the *ngSwitch... chain. This chain of structural directives determine which h1 element renders.

*ngSwitch…表达式中只有一个呈现。 注意div元素内部的[ngSwitch]属性包装了该开关。 这*ngSwitch... potato的值沿*ngSwitch...链传递。 这条结构指令链确定呈现哪个h1元素。

As such, [ngSwitch] is not a structural directive unlike the *ngSwitch… statements. It passes the value along whereas the switch block determines the final layout of HTML.

因此,与*ngSwitch…语句不同, [ngSwitch]不是结构化指令。 它传递值,而switch块确定HTML的最终布局。

Remember that stylization and value passing are not the responsibility of structural directives. That concerns attribute directives. Structural directives determine only the layout.

请记住,风格化和价值传递不是结构性指令的责任。 那涉及属性指令。 结构指令仅确定布局。

管子 (Pipes)

Output data transformations ensure data is in a desirable format by the time it loads onto the user’s screen. Normally data transforms behind the scenes. With pipes, transforming data can take place in the template HTML. Pipes transform template data directly.

输出数据转换可确保数据在加载到用户屏幕上之前处于理想格式。 通常,数据在后台转换。 使用管道,可以在模板HTML中进行数据转换。 管道直接转换模板数据。

Pipes look nice and are convenient. They help keep the component’s class lean of basic transformations. To put it technically, pipes encapsulate data transformation logic.

管道看起来不错,很方便。 它们有助于使组件的类保持基本的转换。 从技术上讲,管道封装了数据转换逻辑。

用例 (Use Cases)

Angular comes prepackaged with a basic set of pipes. Working with a couple of them will develop the intuition to handle the rest. The following list provides three examples.

Angular预包装了一组基本的管道。 与其中的一些人一起工作将发展直觉,以应付其余的一切。 以下列表提供了三个示例。

  • AsyncPipe

    异步管道
  • DatePipe

    DatePipe
  • TitleCasePipe

    TitleCasePipe
异步管道 (AsyncPipe)

This sections requires a basic understanding of Promises or Observables to fully appreciate. The AsyncPipe operates on either of the two. AsyncPipe extracts data from Promises/Observables as output for whatever comes next.

本节要求对承诺或可观察对象有基本的了解,以充分理解。 AsyncPipe在两者之一上运行。 AsyncPipe从Promises / Observables中提取数据作为下一步的输出。

In the case of Obervables, AsyncPipe subscribes automatically to the data source. Regardless of where the data comes from, the AsyncPipe subscribes to the source observable. async is the syntactical name of AsyncPipe as shown below.

对于Obervables,AsyncPipe自动订阅数据源。 无论数据来自何处,AsyncPipe都订阅可观察的源。 async是AsyncPipe的语法名称,如下所示。

<ul *ngFor=“let potato of (potatoSack$ | async); let i=index”>
  <li>Potatoe {{i + 1}}: {{potato}}</li>
</ul>

In the example, potatoSack$ is an Observable pending an upload of potatoes. Once the potatoes arrive, either synchronously or asynchronously, the AsyncPipe receives them as an iterable array. The list element then fills up with potatoes.

在此示例中, potatoSack$是一个Observable,等待上载土豆。 一旦土豆同步或异步到达,AsyncPipe就会以可迭代数组的形式接收它们。 然后,list元素用土豆填满。

DatePipe (DatePipe)

Formatting date strings takes a fair bit of hacking with the JavaScript Date object. The DatePipe provides a powerful way to format dates assuming the given input is a valid time format.

格式化日期字符串需要使用JavaScript Date对象进行相当多的修改。 DatePipe提供了一种强大的方式来格式化日期,前提是给定的输入是有效的时间格式。

TitleCasePipe (TitleCasePipe)

Transforms text to title case. Capitalizes the first letter of each word, and transforms the rest of the word to lower case. Words are delimited by any whitespace character, such as a space, tab, or line-feed character.

将文本转换为标题大小写。 将每个单词的首字母大写,然后将其余单词转换为小写。 单词由任何空格字符定界,例如空格,制表符或换行符。

// example.component.ts

@Component({
  templateUrl: './example.component.html'
})
export class ExampleComponent {
  timestamp:string = ‘2018-05-24T19:38:11.103Z’;
}
<!-- example.component.html -->

<div>Current Time: {{timestamp | date:‘short’}}</div>

The format of the above timestamp is ISO 86011—not the easiest to read. The DatePipe (date) transforms the ISO date format into a more conventional mm/dd/yy, hh:mm AM|PM. There are many other formatting options. All these options are in the official documentation.

以上timestamp的格式为ISO 8601 1-并非最容易阅读。 DatePipe( date )将ISO日期格式转换为更常规的mm/dd/yy, hh:mm AM|PM 。 还有许多其他格式设置选项。 所有这些选项都在官方文档中

创建管道 (Creating Pipes)

While Angular only has a set number of pipes, the @Pipe decorator lets developers create their own. The process begins with ng generate pipe [name-of-pipe], replacing [name-of-pipe] with a preferable filename. This command yields the following:

虽然Angular只有一定数量的管道,但是@Pipe装饰器允许开发人员创建自己的管道。 该过程始于ng generate pipe [name-of-pipe] ,并用首选的文件名替换[name-of-pipe] 。 此命令产生以下内容:

import { Pipe, PipeTransform } from ‘@angular/core’;

@Pipe({
  name: 'example'
})
export class ExamplePipe implements PipeTransform {
  transform(value: any, args?: any): any {
      return null;
  }
}

This pipe template simplifies custom pipe creation. The @Pipe decorator tells Angular the class is a pipe. The value of name: ‘example’, in this case being example, is the value Angular recognizes when scanning template HTML for custom pipes.

该管道模板简化了自定义管道的创建。 @Pipe装饰器告诉Angular该类是管道。 name: 'example'的值name: 'example' (在本例中为example )是Angular在扫描模板HTML中的自定义管道时识别的值。

On to the class logic. The PipeTransform implementation provides the instructions for the transformfunction. This function has special meaning within context of the @Pipe decorator. It receives two parameters by default.

关于类逻辑。 PipeTransform实现提供了有关transform功能的说明。 在@Pipe装饰器的上下文中,此功能具有特殊含义。 默认情况下,它接收两个参数。

value: any is the output that the pipe receives. Think of <div>{{ someValue | example }}</div>. The value of someValue gets passed to the transform function’s value: any parameter. This is the same transform function defined in the ExamplePipe class.

value: any是管道接收的输出。 想想<div>{{ someValue | example }}</div> <div>{{ someValue | example }}</div> 。 someValue的值传递给transform函数的value: any参数。 这与ExamplePipe类中定义的transform函数相同。

args?: any is any argument that the pipe optionally receives. Think of <div>{{ someValue | example:[some-argument] }}</div>. [some-argument] can be replace by any one value. This value gets passed to the transform function’s args?: any parameter. That is, the transform function defined in ExamplePipe's class.

args?: any是管道可选接收的任何参数。 想想<div>{{ someValue | example:[some-argument] }}</div> <div>{{ someValue | example:[some-argument] }}</div>[some-argument]可以替换为任何一个值。 此值将传递到transform函数的args?: any参数。 也就是说,在ExamplePipe的类中定义的transform函数。

Whatever the function returns (return null;) becomes the output of the pipe operation. Take a look at the next example to see a complete example of ExamplePipe. Depending on the variable the pipe receives, it either uppercases or lowercases the input as new output. An invalid or nonexistent argument will cause the pipe to return the same input as output.

函数返回的任何内容( return null; )都将成为管道操作的输出。 查看下一个示例,以查看ExamplePipe的完整示例。 根据管道接收的变量,它会将输入大写还是小写作为新输出。 无效或不存在的参数将导致管道返回与输出相同的输入。

// example.pipe.ts

@Pipe({
  name: 'example'
})
export class ExamplePipe implements PipeTransform {
  transform(value:string, args?:string): any {
    switch(args || null) {
      case 'uppercase':
        return value.toUpperCase();
      case 'lowercase':
        return value.toLowerCase();
      default:
        return value;
    }
  }
}
// app.component.ts

@Component({
  templateUrl: 'app.component.html'
})
export class AppComponent {
  someValue:string = "HeLlO WoRlD!";
}
<!-- app.component.html -->

<!-- Outputs “HeLlO WoRlD!” -->
<h6>{{ someValue | example }}</h6>

<!-- Outputs “HELLO WORLD!” -->
<h6>{{ someValue | example:‘uppercase’ }}</h6>

<!-- Outputs “hello world!” -->
<h6>{{ someValue | example:‘lowercase’ }}</h6>

生命周期挂钩 (Lifecycle Hooks)

Lifecycle hooks are timed methods. They differ in when and why they execute. Change detection triggers these methods. They execute depending on the conditions of the current cycle. Angular runs change detection constantly on its data. Lifecycle hooks help manage its effects.

生命周期挂钩是定时方法。 它们在执行时间和执行方式上有所不同。 更改检测将触发这些方法。 它们根据当前循环的条件执行。 Angular不断对其数据进行更改检测。 生命周期挂钩有助于管理其影响。

An important aspect of these hooks is their order of execution. It never deviates. They execute based off a predictable series of load events produced from a detection cycle. This makes them predictable. Some assets are only available after a certain hook executes. Of course, a hook only execute under certain conditions set in the current change detection cycle.

这些挂钩的重要方面是它们的执行顺序。 它永远不会偏离。 它们基于检测周期产生的一系列可预测的负载事件来执行。 这使它们可预测。 某些资产仅在执行某些挂钩后才可用。 当然,挂钩仅在当前变化检测周期中设置的特定条件下执行。

按执行顺序: (In Order of Execution:)

ngOnChanges (ngOnChanges)

ngOnChanges triggers following the modification of @Input bound class members. Data bound by the @Input() decorator come from an external source. When the external source alters that data in a detectable manner, it passes through the @Input property again.

ngOnChanges在修改@Input绑定类成员ngOnChanges触发。 @Input()装饰器绑定的数据来自外部源。 当外部源以可检测的方式更改该数据时,它将再次通过@Input属性。

With this update, ngOnChanges immediately fires. It also fires upon initialization of input data. The hook receives one optional parameter of type SimpleChanges. This value contains information on the changed input-bound properties.

有了此更新, ngOnChanges立即触发。 输入数据初始化时也会触发。 挂钩接收一个类型为SimpleChanges可选参数。 此值包含有关更改的输入绑定属性的信息。

ngOnInit (ngOnInit)

ngOnInit fires once upon initialization of a component’s input-bound (@Input) properties. The next example will look similar to the last one. The hook does not fire as ChildComponent receives the input data. Rather, it fires right after the data renders to the ChildComponent template.

初始化组件的输入绑定( @Input )属性后, ngOnInit会触发一次。 下一个示例看起来与上一个类似。 当ChildComponent接收输入数据时,该钩子不会触发。 而是在数据渲染到ChildComponent模板后立即触发。

ngDoCheck (ngDoCheck)

ngDoCheck fires with every change detection cycle. Angular runs change detection frequently. Performing any action will cause it to cycle. ngDoCheck fires with these cycles. Use it with caution. It can create performance issues when implemented incorrectly.

ngDoCheck在每个更改检测周期触发。 角行程经常检测变化。 执行任何操作都会导致其循环。 ngDoCheck在这些周期内触发。 请谨慎使用。 如果实施不正确,可能会导致性能问题。

ngDoCheck lets developers check their data manually. They can trigger a new application date conditionally. In conjunction with ChangeDetectorRef, developers can create their own checks for change detection.

ngDoCheck使开发人员可以手动检查其数据。 他们可以有条件地触发新的申请日期。 结合ChangeDetectorRef ,开发人员可以创建自己的检查以进行更改检测。

ngAfterContentInit (ngAfterContentInit)

ngAfterContentInit fires after the component's content DOM initializes (loads for the first time). Waiting on @ContentChild(ren) queries is the hook's primary use-case.

组件的内容DOM初始化(首次加载)后,将触发ngAfterContentInit 。 等待@ContentChild(ren)查询是该挂钩的主要用例。

@ContentChild(ren) queries yield element references for the content DOM. As such, they are not available until after the content DOM loads. Hence why ngAfterContentInit and its counterpart ngAfterContentChecked are used.

@ContentChild(ren)查询产生内容DOM的元素引用。 因此,它们只有在内容DOM加载之后才可用。 因此,为什么要使用ngAfterContentInit及其对应的ngAfterContentChecked

ngAfterContentChecked (ngAfterContentChecked)

ngAfterContentChecked fires after every cycle of change detection targeting the content DOM. This lets developers facilitate how the content DOM reacts to change detection. ngAfterContentCheckedcan fire frequently and cause performance issues if poorly implemented.

ngAfterContentChecked在针对内容DOM的每个更改检测周期之后触发。 这使开发人员可以简化内容DOM对更改检测的React。 ngAfterContentChecked如果执行ngAfterContentChecked可能会经常触发并导致性能问题。

ngAfterContentChecked fires during a component’s initialization stages too. It comes right after ngAfterContentInit.

ngAfterContentChecked在组件的初始化阶段触发。 它ngAfterContentInitngAfterContentInit之后。

ngAfterViewInit (ngAfterViewInit)

ngAfterViewInit fires once after the view DOM finishes initializing. The view always loads right after the content. ngAfterViewInit waits on @ViewChild(ren) queries to resolve. These elements are queried from within the same view of the component.

视图DOM完成初始化后, ngAfterViewInit会触发一次。 视图始终在内容之后立即加载。 ngAfterViewInit等待@ViewChild(ren)查询解决。 从组件的同一视图中查询这些元素。

In the example below, BComponent’s h3 header is queried. ngAfterViewInit executes as soon as the query's results are available.

在下面的示例中,查询BComponent的h3标头。 ngAfterViewInit查询结果可用, ngAfterViewInit执行。

ngAfterViewChecked (ngAfterViewChecked)

ngAfterViewChecked fires after any change detection cycle targeting the component’s view. The ngAfterViewChecked hook lets developers facilitate how change detection affects the view DOM.

ngAfterViewChecked在针对组件视图的任何更改检测周期之后触发。 ngAfterViewChecked挂钩使开发人员可以方便地进行更改检测如何影响视图DOM。

ngOnDestroy (ngOnDestroy)

ngOnDestroy fires upon a component’s removal from the view and subsequent DOM. This hook provides a chance to clean up any loose ends before a component's deletion.

ngOnDestroy在从视图和后续DOM中删除组件时触发。 该挂钩可在删除组件之前清理所有松动的末端。

观看次数 (Views)

Views are almost like their own virtual DOM. Each view contains a reference to a corresponding section of the DOM. Inside a view are nodes that mirror what is in the this section. Angular assigns one view node per DOM element. Each node holds a reference to a matching element.

视图几乎就像它们自己的虚拟DOM。 每个视图都包含对DOM相应部分的引用。 视图内部是反映本节内容的节点。 Angular为每个DOM元素分配一个视图节点。 每个节点都有对匹配元素的引用。

When Angular checks for changes, it checks the views. Angular avoids the DOM under the hood. The views reference the DOM on its behalf. Other mechanisms are in place to ensure that view changes render to the DOM. Conversely, changes to the DOM do not affect the views.

Angular检查更改时,将检查视图。 Angular避免了幕后的DOM。 视图代表DOM引用DOM。 还有其他机制可以确保视图更改呈现给DOM。 相反,对DOM的更改不会影响视图。

Again, views are common across all development platforms besides the DOM. Even if developing for one platform, views are still considered best practice. They guarantee Angular has a correct interpretation of the DOM.

同样,视图在DOM之外的所有开发平台上都是通用的。 即使为一个平台开发,视图仍然被认为是最佳实践。 它们保证Angular对DOM有正确的解释。

Views may not exist on third-party libraries. Direct DOM manipulation is an escape hatch for this kind of scenario. Granted, do not expect the application to function cross-platform.

第三方库上可能不存在视图。 对于这种情况,直接DOM操作是一种逃生方法。 当然,不要期望应用程序可以跨平台运行。

视图类型 (Types of Views)

There are two main types of views: embedded and host.

视图有两种主要类型:嵌入式视图和主机视图。

There also exists view containers. They hold embedded and host views and are often referred to as simple “views”.

还存在视图容器。 它们具有嵌入式和宿主视图,通常称为简单“视图”。

Every @Component class registers a view container (view) with Angular. New components generate a custom selector targeting a certain DOM element. The view attaches to that element wherever it appears. Angular now knows the component exists looking at the view model.

每个@Component类都向Angular注册一个视图容器(视图)。 新组件会生成针对某个DOM元素的自定义选择器。 该视图无论出现在何处都将附加到该元素。 现在,Angular通过查看视图模型知道组件存在。

主机视图和容器 (Host Views and Containers)

Host views host dynamic components. View containers (views) attach automatically to elements already in the template. Views can attach to any element beyond what is unique to component classes.

主机视图承载动态组件。 视图容器(视图)自动附加到模板中已存在的元素。 视图可以附加到任何组件类之外的元素。

Think of the traditional method of component generation. It begins by creating a class, decorating it with @Component, and filling in metadata. This approach occurs for any pre-defined component element of the template.

想想传统的组件生成方法。 首先创建一个类,用@Component装饰它,然后填充元数据。 对于模板的任何预定义组件元素,都会发生这种方法。

Try using the Angular command-line interface (CLI) command: ng generate component [name-of-component]. It yields the following.

尝试使用Angular命令行界面(CLI)命令: ng generate component [name-of-component] 。 它产生以下内容。

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

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

  ngOnInit() { }
}

This creates the component with the selector app-example. This attaches a view container to <app-example></app-example> in the template. If this were the root of the application, its view would encapsulate all other views. The root view marks the beginning of the application from Angular's perspective.

这将使用选择器app-example创建组件。 这会将视图容器附加到模板中的<app-example></app-example> 。 如果这是应用程序的根,则其视图将封装所有其他视图。 从Angular的角度来看,根视图标志着应用程序的开始。

Creating components dynamically and registering them in the Angular view model takes a few extra steps. Structural directives help manage dynamic content (*ngIf, *ngFor, and *ngSwitch…). Directives do not scale to bigger applications however. Too many structural directives complicates the template.

动态创建组件并将其注册到Angular视图模型中需要花费一些额外的步骤。 结构化指令有助于管理动态内容( *ngIf, *ngFor, and *ngSwitch… )。 但是,指令无法扩展到更大的应用程序。 太多的结构指令使模板复杂化。

This is where instantiating components from existing class logic comes in handy. These components need to create a host view that can insert into the view model. Host views holds data for components so that Angular recognizes their structural purpose.

这是从现有类逻辑实例化组件的地方。 这些组件需要创建一个可以插入视图模型的宿主视图。 宿主视图保存组件的数据,以便Angular识别其结构目的。

嵌入式视图 (Embedded Views)

Structural directives create an ng-template surrounding a chunk of HTML content. The directive's host element has a view container attached. This make it so that the content can conditionally render into its intended layout.

结构化指令会在大量HTML内容周围创建一个ng-template 。 指令的host元素具有连接的视图容器。 这样可以使内容可以有条件地呈现为其预期的布局。

The ng-template holds embedded view nodes representing each element within its innerHTML. ng-template is by no means a DOM element. It comments itself out. The tags define the extend of its embedded view.

ng-template包含表示其innerHTML中每个元素的嵌入式视图节点。 ng-template绝不是DOM元素。 它自行注释掉。 标签定义其嵌入式视图的扩展。

Instantiating an embedded view requires no external resources beyond its own reference. The @ViewChild query can fetch that.

实例化嵌入式视图不需要其引用之外的任何外部资源。 @ViewChild查询可以获取该信息。

With the template reference, calling createEmbeddedView from it does the trick. The innerHTML of the reference becomes its own embedded view instance.

使用模板引用,从中调用createEmbeddedView可以解决问题。 引用的innerHTML成为其自己的嵌入式视图实例。

In the next example, <ng-container></ng-container> is a view container. ng-container gets commented out during compilation just like ng-template. Thus it provides an outlet for inserting the embedded view while keeping the DOM lean.

在下一个示例中, <ng-container></ng-container>是一个视图容器。 ng-container就像ng-template一样在编译过程ng-container被注释掉。 因此,它提供了用于在保持DOM精简的同时插入嵌入式视图的出口。

The embedded view template inserts at the layout location of ng-container. This newly inserted view has no additional view encapsulation besides the view container. Remember how that differs from host views (host views attach to their ng-component element wrapper).

嵌入式视图模板将插入ng-container的布局位置。 这个新插入的视图除视图容器外没有其他视图封装。 记住与主机视图有何不同(主机视图附加到其ng-component元素包装器)。

import { Component, AfterViewInit, ViewChild,
ViewContainerRef, TemplateRef } from '@angular/core';

@Component({
  selector: 'app-example',
  template: `
  <h1>Application Content</h1>
  <ng-container #container></ng-container> <!-- embed view here -->
  <h3>End of Application</h3>

  <ng-template #template>
    <h1>Template Content</h1>
    <h3>Dynamically Generated!</h3>
  </ng-template>
  `
})
export class ExampleComponent implements AfterViewInit {
  @ViewChild("template", { read: TemplateRef }) tpl: TemplateRef<any>;
  @ViewChild("container", { read: ViewContainerRef }) ctr: ViewContainerRef;

  constructor() { }

  ngAfterViewInit() {
    const view =  this.tpl.createEmbeddedView(null);
    this.ctr.insert(view);
  }
}

@ViewChild queries for the template reference variable #template. This provides a template reference of type TemplateRef. TemplateRef holds the createEmbeddedView function. It instantiates the template as an embedded view.

@ViewChild查询模板引用变量 #template 。 这提供类型的模板参考TemplateRefTemplateRef拥有createEmbeddedView函数。 它将模板实例化为嵌入式视图。

The single argument of createEmbeddedView is for context. If you wanted to pass in additional metadata, you could do it here as an object. The fields should match up with the ng-template attributes (let-[context-field-key-name]=“value”). Passing null indicates no extra metadata is necessary.

createEmbeddedView的单个参数用于上下文。 如果您想传递其他元数据,则可以在此处作为对象来进行传递。 这些字段应与ng-template属性匹配( let-[context-field-key-name]=“value” )。 传递null表示不需要额外的元数据。

A second @ViewChild query provides a reference to ng-container as a ViewContainerRef. Embedded views only attach to other views, never the DOM. The ViewContainerRef references the view that takes in the embedded view.

第二个@ViewChild查询提供对ng-container的引用作为ViewContainerRef 。 嵌入式视图仅附加到其他视图,而不附加到DOM。 ViewContainerRef引用嵌入视图中的视图。

An embedded view may also insert into the component view of <app-example></app-example>. This approach positions the view at the very end of ExampleComponent’s view. In this example however, we want the content to show up in the very middle where ng-container sits.

嵌入式视图也可以插入<app-example></app-example>的组件视图中。 这种方法将视图放置在ExampleComponent视图的最末端。 但是,在此示例中,我们希望内容显示在ng-container所在的中间位置。

The ViewContainerRef insert function inserts the embedded view into the ng-container. The view content shows ups in the intended location right in the middle of ExampleComponent's view.

ViewContainerRef insert函数嵌入的视图插入ng-container 。 视图内容将显示在ExampleComponent视图中间的预期位置。

路由 (Routing)

Routing is essential. Many modern web applications host too much information for one page. Users should not have to scroll through an entire application’s worth of content either. An application needs to split itself into distinguishable sections.An Angular best practice is to load and configure the router in a separate, top-level module that is dedicated to routing and imported by the root AppModule.

路由至关重要。 许多现代的Web应用程序为一页承载太多信息。 用户也不必滚动浏览整个应用程序的内容。 应用程序需要将自己划分为不同的部分。Angular的最佳实践是在单独的顶级模块中加载和配置路由器,该模块专用于路由并由根AppModule导入。

Users prioritize necessary information. Routing helps them find the application section with such information. Any other information useful to other users may exist on an entirely separate route. With routing, both users can find what they need quickly. Irrelevant details stay obscured behind irrelevant routes.

用户优先考虑必要的信息。 路由帮助他们找到带有此类信息的应用程序部分。 对其他用户有用的任何其他信息都可以存在于完全独立的路径上。 通过路由,两个用户都可以快速找到他们需要的东西。 不相关的细节在不相关的路线后面被遮盖。

Routing excels at sorting and restricting access to application data. Sensitive data should never display to unauthorized users. Between every route the application may intervene. It can examine a user’s session for authentication purposes. This examination determines what the route renders if it should render at all. Routing gives developers the perfect chance to verify a user before proceeding.

路由擅长于排序和限制对应用程序数据的访问。 敏感数据绝不能显示给未经授权的用户。 在每条路线之间,应用程序都可能会介入。 它可以检查用户的会话以进行身份​​验证。 该检查确定路线是否应该渲染。 路由为开发人员提供了在继续操作之前验证用户的绝佳机会。

As for Angular, routing takes up its own entire library within the framework. All modern front-end frameworks support routing, and Angular is no different. Routing happens from the client-side using either hash or location routing. Both styles allow the client to manage its own routes. No additional assistance from the server is necessary past the initial request.

至于Angular,路由在框架内占用了它自己的整个库。 所有现代的前端框架都支持路由,而Angular也不例外。 使用散列或位置路由从客户端进行路由。 两种样式都允许客户端管理自己的路由。 在初始请求之后,无需服务器的其他帮助。

基本路由 (Basic Routing)

Routing utilities export with RouterModule available from @angular/router. It is not part of the core library since not all applications require routing. The most conventional way to introduce routing is as its own feature module.

路由实用程序可通过@angular/router RouterModule导出。 它不是核心库的一部分,因为并非所有应用程序都需要路由。 引入路由的最传统方法是作为其自身的功能模块

As route complexity grows, having it as its own module will promote the root module’s simplicity. Keeping it stupid simple without compromising functionality constitutes good design for modules.

随着路由复杂度的增加,将其作为自己的模块将促进根模块的简单性。 在不影响功能的情况下保持愚蠢的简单性构成了模块的良好设计。

import { NgModule } from '@angular/core';
import { RouterModule, Routes } from '@angular/router';

import { AComponent } from '../../components/a/a.component';
import { BComponent } from '../../components/b/b.component';

// an array of soon-to-be routes!
const routes: Routes = [];

@NgModule({
  imports: [ RouterModule.forRoot(routes) ],
  exports: [ RouterModule ]
})
export class AppRoutingModule { }

.forRoot(...) is a class function available from the RouterModule class. The function accepts an array of Route objects as Routes. .forRoot(...) configures routes for eager-loading while its alternative .forChild(...) configures for lazy-loading.

.forRoot(...)是RouterModule类中可用的类函数。 该函数接受Route对象数组作为Routes.forRoot(...)配置路由以进行.forChild(...)加载,而其替代.forChild(...)配置为延迟加载。

Eager-loading meaning the routes load their content into the application from the get-go. Lazy-loading happens on-demand. The focus of this article is eager-loading. It is the default approach for loading in an application. The RouterModule class definition looks something like the next block of code.

急切加载意味着路由从一开始就将其内容加载到应用程序中。 延迟加载按需进行。 本文的重点是急切加载。 这是在应用程序中加载的默认方法。 RouterModule类定义类似于下一个代码块。

@NgModule({
  // … lots of metadata ...
})
export class RouterModule {
  forRoot(routes: Routes) {
    // … configuration for eagerly loaded routes …
  }

  forChild(routes: Routes) {
    // … configuration for lazily loaded routes …
  }
}

Do not worry about the configuration details the example omits with comments. Having a general understanding will do for now.

不必担心示例中带有注释的配置详细信息。 大致了解现在就可以了。

Notice how AppRoutingModule imports the RouterModule while also exporting it. This makes sense given AppRoutingModule is a feature module. It imports into the root module as a feature module. It exposes RouterModule directives, interfaces, and services to the root component tree.

请注意AppRoutingModule如何导入RouterModule并同时将其导出。 鉴于AppRoutingModule是功能模块,这是有道理的。 它将作为功能模块导入到根模块中。 它将RouterModule指令,接口和服务公开给根组件树。

This explains why AppRoutingModule must export RouterModule. It does so for the sake of the root module’s underlying component tree. It needs access to those routing utilities!

这解释了为什么AppRoutingModule必须导出RouterModule。 这样做是为了根模块的基础组件树。 它需要访问那些路由实用程序!

import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';

import { AppComponent } from './app.component';
import { AComponent } from './components/a/a.component';
import { BComponent } from './components/b/b.component';
import { AppRoutingModule } from './modules/app-routing/app-routing.module';

@NgModule({
  declarations: [
    AppComponent,
    AComponent,
    BComponent
  ],
  imports: [
    AppRoutingModule, // routing feature module
    BrowserModule
  ],
  providers: [],
  bootstrap: [ AppComponent ]
})
export class AppModule { }

The AppRoutingModule token imports from the very top. Its token inserts into the root module’s imports array. The root component tree may now utilize the RouterModule library. That includes its directives, interfaces, and services as already mentioned. Big thanks goes to AppRoutingModule for exporting RouterModule!

AppRoutingModule令牌从最顶部导入。 它的令牌插入到根模块的imports数组中。 根组件树现在可以利用RouterModule库。 如前所述,这包括其指令,接口和服务。 非常感谢AppRoutingModule导出RouterModule!

The RouterModule utilities will come in handy for the root’s components. The basic HTML for AppComponent makes use of one directive: router-outlet.

RouterModule实用程序将对根目录的组件派上用场。 AppComponent的基本HTML使用一个指令: router-outlet

<!-- app.component.html -->

<ul>
  <!-- routerLink(s) here -->
</ul>
<router-outlet></router-outlet>
<!-- routed content appends here (AFTER THE ELEMENT, NOT IN IT!) -->

routerLink is an attribute directive of RouterModule. It will attach to each element of <ul></ul> once the routes are setup. router-outlet is a component directive with interesting behavior. It acts more as a marker for displaying routed content. Routed content results from navigation to a specific route. Usually that means a single component as configured in AppRoutingModule

routerLinkrouterLink的属性指令。 设置路由后,它将附加到<ul></ul>每个元素。 router-outlet是具有有趣行为的组件指令。 它更多地用作显示路由内容的标记。 路由内容是从导航到特定路由的结果。 通常,这意味着在AppRoutingModule中配置的单个组件

The routed content renders right after <router-outlet></router-outlet>. Nothing renders inside of it. This does not make too much of a considerable difference. That said, do not expect router-outlet to behave like a container for routed content. It is merely a marker for appending routed content to the Document Object Model (DOM).

路由的内容在<router-outlet></router-outlet>之后呈现。 里面什么也没有。 这并没有太大的区别。 就是说,不要指望router-outlet表现得像是路由内容的容器。 它只是用于将路由内容附加到文档对象模型(DOM)的标记。

The first question to address is what routes will this application consume? Well, there are two components: AComponent and BComponent. Each one should have its own route. They can render from AppComponent’s router-outlet depending on the current route location.

要解决的第一个问题是此应用程序将消耗哪些路由? 好,有两个组件:AComponent和BComponent。 每个人都应该有自己的路线。 它们可以根据当前路线位置从AppComponent的router-outlet进行渲染。

The route location (or path) defines what appends to a website's origin (e.g. http://localhost:4200) through a series of slashes (/).

路由位置(或路径)定义了通过一系列斜杠( / )附加到网站来源 (例如http:// localhost:4200 )的内容。

// … same imports from before …

const routes: Routes = [
  {
    path: 'A',
    component: AComponent
  },
  {
    path: 'B',
    component: BComponent
  }
];

@NgModule({
  imports: [ RouterModule.forRoot(routes) ],
  exports: [ RouterModule ]
})
export class AppRoutingModule { }

http://localhost:4200/A renders AComponent from AppComponent’s router-outlet. http://localhost:4200/B renders BComponent. You need a way to route to these locations without using the address bar though. An application should not rely upon a web browser's address bar for navigation.

http://localhost:4200/A从AppComponent的router-outlet out呈现AComponent。 http://localhost:4200/B呈现BComponent。 您需要一种无需使用地址栏即可路由到这些位置的方法。 应用程序不应依赖Web浏览器的地址栏进行导航。

The global CSS (Cascading Style-sheets) supplements the HTML below it. An application’s router link ought to have a pleasant appearance. This CSS applies to all other examples too.

全局CSS(层叠样式表)补充了其下方HTML。 应用程序的路由器链接应具有愉悦的外观。 该CSS也适用于所有其他示例。

/* global styles.css */

ul li {
  cursor: pointer;
  display: inline-block;
  padding: 20px;
  margin: 5px;
  background-color: whitesmoke;
  border-radius: 5px;
  border: 1px solid black;
}

ul li:hover {
  background-color: lightgrey;
}
<!-- app.component.html -->

<ul>
  <li routerLink="/A">Go to A!</li>
  <li routerLink="/B">Go to B!</li>
</ul>
<router-outlet></router-outlet>

This is basic routing! Clicking either of the routerLink elments routes the web address. It reassigns it without refreshing the web browser. Angular’s Router maps the routed address to the Routes configured in AppRoutingModule. It matches the address to the path property of a single Route object within the array. First match always wins, so match-all routes should lie at the very end of the Routes array.

这是基本的路由! 单击任一routerLink元素将路由该网址。 它会重新分配它,而不刷新Web浏览器。 Angular的Router将路由的地址映射到AppRoutingModule中配置的Routes 。 它将地址与数组中单个Route对象的path属性匹配。 首次比赛总是获胜,因此所有比赛路线都应位于Routes数组的末尾。

Match-all routes prevent the application from crashing if it cannot match the current route. This can happen from the address bar where the user may type in any route. For this, Angular provides a wildcard path value ** that accepts all routes. This route usually renders a PageNotFoundComponent component displaying “Error 404: Page not found”.

全部匹配路由可以防止应用程序如果无法匹配当前路由而崩溃。 这可以从用户可以在其中输入任何路线的地址栏中发生。 为此,Angular提供了一个通配符路径值** ,该值可以接受所有路由。 此路由通常会渲染一个显示“错误404:找不到页面”的PageNotFoundComponent组件。

// … PageNotFoundComponent imported along with everything else …

const routes: Routes = [
  {
    path: 'A',
    component: AComponent
  },
  {
    path: 'B',
    component: BComponent
  },
  {
    path: '',
    redirectTo: 'A',
    pathMatch: 'full'
  },
  {
    path: '**',
    component: PageNotFoundComponent
  }
];

The Route object containing redirectTo keeps the PageNotFoundComponent from rendering as a result of http://localhost:4200. This is the applications home route. To fix this, redirectTo reroutes the home route to http://localhost:4200/A. http://localhost:4200/A indirectly becomes the application’s new home route.

包含redirectToRoute对象使PageNotFoundComponent不会由于http://localhost:4200而呈现。 这是应用程序的本地路由。 要解决此问题, redirectTo将本地路由重新路由到http://localhost:4200/A http://localhost:4200/A间接成为应用程序的新本地路由。

The pathMatch: 'full' tells the Route object to match against the home route (http://localhost:4200). It matches the empty path.

pathMatch: 'full'告诉Route对象与本地路由( http://localhost:4200 )匹配。 它匹配空路径。

These two new Route objects go at the end of the array since first match wins. The last array element (path: '**') always matches, so it goes last.

由于首场比赛获胜,这两个新的Route对象位于数组的末尾。 最后一个数组元素( path: '**' )始终匹配,因此位于最后。

There is one last thing worth addressing before moving on. How does the user know where he or she is in the application relative to the current route? Sure there may be content specific to the route, but how is user supposed to make that connection? There should be some form of highlighting applied to the routerLinks. That way, the user will know which route is active for the given web page.

在继续之前,还有最后一件事值得解决。 用户如何知道他或她在应用程序中相对于当前路线的位置? 当然,可能存在特定于该路线的内容,但是用户应该如何建立该连接? 应该对路由器链接应用某种形式的突出显示。 这样,用户将知道哪个路由对于给定的网页是活动的。

This is an easy fix. When you click a routerLink element, Angular’s Router assigns focus to it. This focus can trigger certain styles which provide useful feedback to the user. The routerLinkActive directive can track this focus for the developer.

这是一个简单的修复。 当您单击routerLink元素时,Angular的Router会为其分配焦点 。 该焦点可以触发某些样式,这些样式可以为用户提供有用的反馈。 routerLinkActive指令可以为开发人员跟踪此焦点。

<!-- app.component.html -->

<ul>
  <li routerLink="/A" routerLinkActive="active">Go to A!</li>
  <li routerLink="/B" routerLinkActive="active">Go to B!</li>
</ul>
<router-outlet></router-outlet>

The right assignment of routerLinkActive represents a string of classes. This example portrays only one class (.active), but any number of space-delimited classes may apply. When the Router assigns focus to a routerLink, the space-delimited classes apply to the host element. When the focus shifts away, the classes get removed automatically.

正确的routerLinkActive分配表示一串类。 本示例仅描绘一个类( .active ),但是可以应用任何数量的以空格分隔的类。 当Router焦点分配给routerLink时,以空格分隔的类适用于主机元素。 当焦点移开时,这些类将自动删除。

/* global styles.css */

.active {
  background-color: lightgrey !important;
}

Users can now easily recognize how the current route and the page content coincide. lightgreyhighlighting applies to the routerLink matching the current route. !important ensures the highlighting overrides inline stylings.

用户现在可以轻松地识别当前路线和页面内容的重合方式。 lightgrey高亮适用于routerLink匹配当前的路线。 !important确保突出显示覆盖内联样式。

翻译自: https://www.freecodecamp.org/news/the-best-angular-examples/

规格示例

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值