10 天学会 Angular - 第 3 天






4.98/5 (20投票s)
在这篇文章中,我们将学习Templates, Events, Models, Directives 等。
- 下载 Lab_2 - 7.8 KB
- 下载 Lab_3 - 8.5 KB
- 下载 Lab_4 - 8.1 KB
- 下载 Lab_5 - 8.2 KB
- 下载 Lab_6 - 8.4 KB
- 下载 Lab_7 - 9.3 KB
- 下载 Lab_8 - 9.5 KB
- 下载 Lab_9 - 9.7 KB
- 下载 Lab_10 - 9.9 KB
如果你对这篇文章感兴趣,说明你已经了解如何
- 安装 NodeJs 并获取 npm
- 安装 TypeScript 编译器并使用它
- 安装 lite-server 并使用它
- 设置一个基本的 Angular 项目
- 使用 Angular 创建一个简单的“
Hello World
”应用程序
和
- 对 TypeScript 有基本的了解
今天,我们将通过更多的实验和演示,将我们的 Angular 技能提升到一个新的水平。让我们开始吧。
预先设置
在继续任何演示之前,我想让你做两件事。
- 打开命令提示符,导航到“TypeScriptFiles”文件夹,然后键入“
tsc -w
”命令以在监视模式下启动 TypeScript 编译器。这将确保每次 TypeScript 文件更改时,它都会自动重新编译。每次更改后都不需要手动重新编译。
- 打开另一个命令提示符,导航到“AngularProject”文件夹,然后键入“
lite-server
”命令来启动 Web 服务器。它将自动启动浏览器(Internet Explorer)。从地址栏复制 URL,打开 Chrome 并将相同的 URL 粘贴到地址栏。
(注意:Chrome 在 JavaScript 调试方面是最好的,如果你愿意,也可以在自己喜欢的浏览器中进行测试。)
向前看,任何时候“AngularProject”文件夹中的任何文件发生更改,浏览器都会自动刷新。自动刷新是“
lite-server
”的功能。
完整系列
- 第 1 天 – 第 1 部分
- 第 1 天 – 第 2 部分
- 第 2 天
- 第 3 天
- 第 4 天 – 第 1 部分
- 第4天 - 执行技巧
- 第 4 天 – 第 2 部分
- 第 4 天 – 第 3 部分
- 第 5 天(即将推出)
- 第 6 天(即将推出)
- 第 7 天(即将推出)
- 第 8 天(即将推出)
- 第 9 天(即将推出)
- 第 10 天(即将推出)
目录
- 预先设置
- Lab 2 – 模板 URL 介绍
- Lab 3 – 使用相对 URL
- Lab 4 – 插值
- Lab 5 – 属性绑定
- Lab 6 – 在 Angular 中处理事件
- Lab 7 – 处理复杂对象
- Lab 8 – 处理集合
- Lab 9 - 数据录入屏幕
- Lab 10 – 条件渲染
- 摘要
- 历史
Lab 2 – 模板 URL 介绍
在上一个演示中,我们创建了“AppComponent
”。Angular 组件是两件事的组合。
- 一个 TypeScript 类,称为
AppComponent
– 它被称为ViewClass
或Component
类。我们很快就会讨论它的实际用途。 - 模板 - 纯粹是 HTML,代表我们的 UI。
在当前的演示中,以上两件事都写在同一个 TypeScript 文件中。许多人(包括我)更喜欢将 HTML 写入独立的文件中,并实现清晰的关注点分离。
可以使用“templateUrl
”来实现。让我们看看如何实现。
步骤 1 – 创建组件文件夹
在“AppModule”文件夹中创建一个名为“AppComponent”的新文件夹。(提醒一下,“AppModule”位于“TypeScriptFiles\AppModule”文件夹中。)
步骤 2 – 移动组件
将“app.component.ts”、“app.component.js”和“app.component.js.map”文件移到“AppComponent”文件夹中。
步骤 3 – 更正引用
按如下方式更改“AppModule
”中的 import
语句
import {AppComponent} from "./AppComponent/app.component"
完整的 AppModule
代码如下所示
import {NgModule} from "@angular/core"
import {AppComponent} from "./AppComponent/app.component"
import {BrowserModule} from "@angular/platform-browser"
@NgModule({
declarations:[AppComponent],
bootstrap:[AppComponent],
imports:[BrowserModule]
})
export class AppModule{
}
步骤 4 – 编译并测试输出
为了确保一切正常,让我们进行一次测试。转到浏览器。
您应该能够看到以下输出
步骤 5 – 创建模板文件
在“AppComponent”文件夹中创建一个名为“app.component.html”的新文件,并在其中放入以下内容
<h1>Welcome to Learn Angular in 10 days series</h1>
<i>Here is the Day 3</i>
步骤 6 – 将模板附加到组件
在附加到“AppComponent
”类的“Component
”装饰器中使用“templateUrl
”选项而不是“template
”选项,如下所示
import {Component} from "@angular/core"
@Component({
selector:'app-component',
templateUrl:'./app.component.html'
}
)
export class AppComponent{
}
步骤 7 - 编译并测试输出
转到浏览器。
检查错误。如您所见,在根文件夹中搜索了‘app.component.html’。
步骤 8 – 更改模板 URL
“templateURL
”是相对的,但相对于“index.html”,而不是它的 TypeScript 文件。将“templateURL
”更改为“./TypeScriptFiles/AppModule/AppComponent/app.component.html”,如下所示。完整代码如下
import {Component} from "@angular/core"
@Component({
selector:'app-component',
templateUrl:'./TypeScriptFiles/AppModule/AppComponent/app.component.html'
}
)
export class AppComponent{
}
步骤 9 - 编译并测试输出
转到浏览器。
Lab 3 – 使用相对 URL
在上一个实验中,我们只是将 HTML 从 TypeScript 文件中取出并放入一个独立的 HTML(模板)文件中。唯一的问题是“templateUrl
”相对于“index.html”。
如果你想让“templateUrl
”相对于相应的“.ts”文件,那么这个实验就是为你准备的。
这可以通过使用一个名为“systemjs-angular-loader.js”的 SystemJs 插件来实现。SystemJs 支持外部插件,我们可以用它们来扩展 SystemJs 的现有行为。“systemjs-angular-loader.js”动态地将“templateUrl
”中的“component-relative
”路径转换为绝对路径。
让我们进行演示。
步骤 1 – 下载插件
这个插件是由 Angular 团队创建的,它将包含在 Angular 团队提供的快速启动设置中。链接如下
从上面的链接下载 zip 文件并解压。文件“systemjs-angular-loader.js”位于“src”文件夹内。
(以后我们会有一个详细的演示来解释这个快速启动项目,现在我们手动完成所有事情,并理解所有内容的本质。)
步骤 2 – 包含插件
复制解压后的插件并粘贴到“AngularProject”文件夹中。现在打开“system.config.js”并添加插件支持,如下所示
...
packages: {
'TypeScriptFiles': {
defaultExtension: 'js',
meta: {
'./*.js': {
loader: 'systemjs-angular-loader.js'
}
}
},
rxjs: {//New line
defaultExtension: 'js'
…
查看添加的新“meta
”选项。
完整的“system.config.js”
(function (global) {
System.config({
map: {
'@angular/core': '/node_modules/@angular/core/bundles/core.umd.js',
'@angular/common': '/node_modules/@angular/common/bundles/common.umd.js',
'@angular/compiler': '/node_modules/@angular/compiler/bundles/compiler.umd.js',
'@angular/platform-browser':
'/node_modules/@angular/platform-browser/bundles/platform-browser.umd.js',
'@angular/platform-browser-dynamic':
'/node_modules/@angular/platform-browser-dynamic/bundles/platform-browser-dynamic.umd.js',
'@angular/http': '/node_modules/@angular/http/bundles/http.umd.js',
'@angular/router': '/node_modules/@angular/router/bundles/router.umd.js',
'@angular/forms': '/node_modules/@angular/forms/bundles/forms.umd.js',
'rxjs':'/node_modules/rxjs',//New line
},
packages: {
'TypeScriptFiles': {
defaultExtension: 'js',
meta: {
'./*.js': {
loader: 'systemjs-angular-loader.js'
}
}
},
rxjs: {//New line
defaultExtension: 'js'
}
}
});
})(this);
步骤 3 – 更改组件
按如下方式将“templateUrl
”值更改为相对路径
import {Component} from "@angular/core"
@Component({
selector:'app-component',
templateUrl:'./app.component.html'
}
)
export class AppComponent{
}
步骤 4 - 编译并测试输出
转到浏览器。
如您所见,演示现在也使用相对 URL 工作了。
注意
在 Angular 项目中使用 SystemJs 作为模块加载器不是强制性的。你也可以选择“requireJs
”或其他。对于其他模块加载器,你需要选择之前的“Lab 2”方法来指定 URL,或者检查你的新模块加载器的文档以获得此类支持。
我建议你现在不要深入研究 SystemJs,而是专注于 Angular 学习。你以后可以用其他学习资源详细学习“SystemJs
”。
在本系列的后续内容中,我们将有一个演示,届时我们将通过移除 SystemJs 并使用 WebPack 来完成工作,从而改进我们的项目。目前,请继续使用它。
Lab 4 – 插值
在这个演示中,我们将探索一个称为插值的 Angular 功能。
正如我之前所说,Angular 组件是两件事的组合。
- 模板 – (也称为视图)它代表组件的 UI 部分。
- 视图类/组件类 – 一个用“
Component
”装饰器装饰的自定义类。它封装了所需的 UI 数据和 UI 逻辑。
“插值是在组件模板中显示动态数据的一种方式”。它使用双大括号({{...}})编写。
让我们通过演示来理解。
步骤 1 – 初始化组件数据
打开‘app.component.ts’文件,在 AppComponent
类中创建两个变量,并在“Constructor
”中简单地为它们赋一个虚拟值。
import {Component} from "@angular/core"
@Component({
selector:'app-component',
templateUrl:'./app.component.html'
}
)
export class AppComponent{
CompnayUrl:string;
CompanyName:string;
constructor(){
this.CompanyName="Train IT";
this.CompnayUrl="http://JustCompile.com";
}
}
步骤 2 – 显示组件数据
现在,按如下方式更改模板文件“app.component.html”
<h1>Welcome to Learn Angular in 10 days series - Day 3</h1>
Company Name: <b>{{CompanyName}}</b>
<br>
Click <a href="{{CompanyUrl}}">here</a> to visit.
您可以看到插值在两个地方被使用。一个在粗体标签之间,第二个作为“href
”值。
步骤 4 - 编译并测试输出
转到浏览器。
非常简单但实用的例子。
Lab 5 – 属性绑定
属性绑定是指将组件类中的变量绑定到模板中某个 HTML 元素的属性。这样的属性称为“输入属性”。
你是否感到困惑?让我们做一个非常快速的演示。
步骤 1 – 在 AppComponent 模板中实现属性绑定
按如下方式更改“app.component.html”中的超链接
<a [href]="CompanyUrl">here</a>
你注意到区别了吗?这次没有插值,而且“href
”被包裹在“[
”和“]
”之间。
这称为“属性绑定”– AppComponent
类的“CompanyUrl
”变量绑定到“a
”元素的“href
”属性,在这个例子中“href
”被称为“输入属性”。
步骤 2 - 编译并测试输出
你将看到与之前完全相同的输出。这证明了插值和属性绑定做了同样的事情。但事实是,属性绑定不仅仅是显示值。让我们通过演示来理解。
步骤 3 – 更改组件类
在 AppComponent
类中添加一个名为“IsChecked
”的新布尔类型变量。
...
export class AppComponent{
CompnayUrl:string;
CompanyName:string;
IsChecked:boolean;
constructor(){
this.CompanyName="Train IT";
this.CompnayUrl="http://www.JustCompile.com";
this.IsChecked=true;
}
}
步骤 4 - 更改模板
在模板中创建一个复选框控件,并将“IsChecked
”属性与 HTML 元素的“checked
”属性一起使用。
<h1>Welcome to Learn Angular in 10 days series - Day 3</h1>
Company Name: <b>{{CompanyName}}</b>
<br>
Is Active: <input type="checkbox" checked={{IsChecked}}>
<br>
Click <a href="{{CompnayUrl}}">here</a> to visit.
步骤 5 - 编译并测试输出
在浏览器中查看输出。
如您所见,Checkbox
被选中了。
步骤 6 – 更改 IsChecked
在 AppComponent
构造函数中,将“IsChecked
”更改为 false
。
...
constructor(){
this.CompanyName="Train IT";
this.CompnayUrl="http://www.JustCompile.com";
this.IsChecked=false;
}
...
步骤 7 - 编译并测试输出
在浏览器中查看输出。
Checkbox
仍然被选中。
步骤 8 – 在模板中实现属性绑定
...
Is Active: <input type="checkbox" [checked]="IsChecked">
...
步骤 9 - 编译并测试输出
在浏览器中查看输出。
哇!:) Checkbox
现在被取消选中了。
步骤 10 – 更改 IsChecked
在 AppComponent
构造函数中,将“IsChecked
”更改为 true
。
...
constructor(){
this.CompanyName="Train IT";
this.CompnayUrl="http://www.JustCompile.com";
this.IsChecked=true;
}
...
步骤 11 - 编译并测试输出
在浏览器中查看输出。
Checkbox
现在又回到了选中状态。
插值 vs 属性绑定
插值会调用变量的“toString
”函数,然后设置值。所以值将始终是 string
,而在属性绑定中,数据类型将被保留。
所以,简单来说 – 当变量是 string
类型时,插值是一个不错的选择,但对于其他数据类型,则首选属性绑定。
对于 string
值,插值更受欢迎,因为在插值中连接更容易。
请查看下面的示例
<p>{{FirstName}} – {{LastName}}</p>
它将简单地显示“FirstName
”和“LastName
”的连接,中间用连字符(-)分隔。
示例 – 当 FirstName
是“Sukesh
”而 LastName
是“Marla
”时,它将显示以下输出
Sukesh – Marla
Lab 6 – 在 Angular 中处理事件
在这个演示中,我们将看到事件绑定(也称为输出属性)的实际应用。
步骤 1 – 更改模板
在‘app.component.html’中添加一个简单的按钮。
<h1>Welcome to Learn Angular in 10 days series - Day 3</h1>
Company Name: <b>{{CompanyName}}</b>
<br>
Is Active: <input type="checkbox" [checked]="IsChecked">
<br>
Click <a href="{{CompnayUrl}}">here</a> to visit.
<br>
<input type="button" value="ChangeValue" (click)="UpdateValue()">
在上面的 HTML 中,“input
”标签有一个特殊的属性称为“click
”,它被写在“(
”和“)
”之间。这是“输出属性”。这是在 Angular 应用程序中处理事件的一种方式。
步骤 2 – 定义事件处理程序
打开‘app.component.ts’。在 AppComponent
类中,创建如下一个新的方法“UpdateValue
”
...
IsChecked:boolean;
constructor(){
this.CompanyName="Train IT";
this.CompnayUrl="http://www.JustCompile.com";
this.IsChecked=false;
}
UpdateValue():void{
this.CompanyName="Just Compile";
this.CompnayUrl="http://www.sukesh-Marla.com";
this.IsChecked=true;
}
}
步骤 3 – 编译并测试输出
打开浏览器。您将看到以下输出。
当点击“ChangeValue
”按钮时,组件类中的“UpadateValue
”函数被调用。这称为事件绑定,并且“click
”是示例中的输出属性。
按钮点击后,整个 UI 会使用新值重新渲染。这是因为 Angular 有一个称为更改检测的机制。更改检测是一种机制,它使 UI 与数据保持同步。每次数据更改时,UI 都会重新渲染。我们将在本系列的后续内容中更详细地讨论更改检测。
Lab 7 – 处理复杂对象
在下一个实验中,我们将了解如何在 Angular 中处理复杂对象。
步骤 1 – 创建模型
在编程世界中,Model 代表数据。让我们在我们的项目中也使用相同的术语。在“AppModule”文件夹中创建一个名为“Models”的新文件夹。
然后,在“Models”文件夹中创建一个名为“Employee.ts”的新 TypeScript 文件,如下所示
export class Employee{
FName:string;
LName:string;
Salary:number;
}
步骤 2 – 在组件类中使用模型
现在是时候重新定义 AppComponent
类了。
删除 AppComponent
中的所有现有代码,然后创建一个类型为 Employee
的新全局变量,并用虚拟值初始化它。这是完整代码。
import {Component} from "@angular/core"
import {Employee} from "../Models/Employee"
@Component({
selector:'app-component',
templateUrl:'./app.component.html'
}
)
export class AppComponent{
emp:Employee;
constructor(){
this.emp=new Employee();
this.emp.FName="Sukesh";
this.emp.LName="Marla";
this.emp.Salary=10000;
}
}
步骤 3 – 在模板中显示模型数据
最后,让我们重新定义模板文件“app.component.html”。这可以通过插值轻松完成。代码如下。
<h1>Welcome to Learn Angular in 10 days series - Day 3</h1>
Employee Name: {{emp.FName}} {{emp.LName}}
<br>
Salary: {{emp.Salary}}
步骤 3 – 编译并测试输出
打开浏览器。您将看到以下输出
简单的例子。
理解项目
正如我在第一天承诺的那样,我们将在一天结束时创建一个简单的 Angular 项目。现在是时候开始了。
我们将一步一步地创建项目。有时,我们会创建一些不符合最佳实践的东西。但没关系,我们会这样做,讨论其中的问题,然后采用最佳实践。
在学习方面,“我们应该学习一种技术的好坏实践”。
让我们开始理解我们要开发的内容。
上面的 UI 是 Employee
UI。我们将为 Customer
、Product
、Customer
和 Supplier
创建一些类似的 UI。
让我们一步一步地开始开发。
Lab 8 – 处理集合
让我们开始在单个 UI 中显示多个 Employees
。
为了做到这一点,我们必须使用一个非常有趣的 Angular 功能,那就是“属性指令”。
步骤 1 – 准备组件类
打开“app.component.ts”文件。删除 AppComponent
中的所有现有代码,然后创建一个类型为 Array<Employee>
的新全局变量,并用虚拟值初始化它。这是完整代码。
import {Component} from "@angular/core"
import {Employee} from "../Models/Employee"
@Component({
selector:'app-component',
templateUrl:'./app.component.html'
}
)
export class AppComponent{
Employees:Array<Employee>;
constructor(){
this.Employees =new Array<Employee>();
let e1=new Employee();;
e1.FName="Sukesh";
e1.LName="Marla";
e1.Salary=10000;
this.Employees.push(e1);
let e2=new Employee();;
e2.FName="Gabbar";
e2.LName="Singh";
e2.Salary=20000;
this.Employees.push(e2);
let e3=new Employee();;
e3.FName="Dragon";
e3.LName="Hunter";
e3.Salary=30000;
this.Employees.push(e3);
}
}
步骤 2 – 重新定义模板
现在为了显示多个 Employees
,我们必须使用 HTML“table
”标签。挑战在于创建“tr
”标签,因为它需要动态创建。对于列表中的每个 Employee
,都应该创建一个“tr
”。
作为最佳实践,Angular 项目中的所有 DOM 操作都必须在不直接访问组件类中的 DOM 的情况下进行。我们将在整个系列中探讨实现这一目标的各种方法。
对于我们当前的需求,我们将使用一个名为“*ngFor
”的 Angular 指令。
“指令在附加时会改变 HTML 元素的默认行为。”
例如,“*ngFor
”指令根据提供的表达式重复主机元素。
打开“app.component.html”,删除现有内容,并在此处放入以下内容。
<h1>Employee</h1>
<table border="1" >
<tr>
<th>Emp Name</th>
<th>Salary </th>
</tr>
<tr *ngFor="let emp of Employees">
<td>{{emp.FName}} {{emp.LName}}</td>
<td>{{emp.Salary}}</td>
</tr>
</table>
查看上面表格中的第二个“tr
”。您会注意到它使用了“*ngFor
”。
让我们来分析这个例子中提供的表达式,它是“let emp of Employees
”。
Angular 迭代“Employees
”(这是一个“Employee
”数组),然后为列表中的每个项目创建一个行(“tr
”)。在当前迭代中,“emp
”将被设置为单个 Employee
项。
步骤 3 – 编译并测试输出
打开浏览器。您将看到以下输出
在本系列的后续内容中,我们将显示真实数据而不是硬编码的数据。
Lab 9 - 数据录入屏幕
在这个实验中,我们将重点放在我们项目的“数据录入”部分。
步骤 1 – 创建数据录入部分
打开‘app.component.html’并将以下 HTML 追加到其中。
<br>
<div>
FName: <input type="text"><br>
LName: <input type="text"><br>
Salary: <input type="text"><br>
<input type="button" value="Save" (click)="SaveEmployee()">
</div>
注意:请确保您已将上述 HTML 追加到现有 HTML 中。(不要替换它。)
步骤 2 – 定义 SaveEmployee
打开 app.component.ts 并按如下方式定义 SaveEmployee
方法
SaveEmployee():void{
let e1=new Employee();
e1.FName="F1";
e1.LName="L1";
e1.Salary=40000;
this.Employees.push(e1);
}
步骤 3 – 编译并测试输出
打开浏览器。您将看到以下输出。
如您所见,我们只需向集合中添加一个新项,UI 就会自动重新渲染。这是因为“更改检测”。
我们有一个关于输入控件的非常详细的实验,届时我们将讨论将输入值获取到组件类的各种方法。目前的例子是插入硬编码的员工,我们就坚持这样做。
Lab 10 – 条件渲染
目前的 UI 同时显示 Employee
列表和数据录入屏幕,但根据我们的要求,一次只能显示一个。
在这个演示中,我们将在我们的项目中实现条件渲染。
让我们开始实现它。
规划逻辑
为了实现我们当前的需求(条件渲染),我们将执行以下步骤。
在组件类中,我们将进行以下更改
- 创建一个布尔变量“
IsAddNew
”,它将表示 UI 中的当前条件。 - 创建一个“
ShowAddNew
”函数,它将“IsAddNew
”设置为true
- 创建一个“
HideAddNew
”函数,它将“IsAddNew
”设置为false
- 在现有的“
SaveEmployee
”函数中,将“IsAddNew
”设置为false
在模板端,我们将使用 HTML 的“hidden
”属性结合 Angular 中的属性绑定。
让我们实际操作并更好地理解它。
步骤 1 – 重新设计模板
让我们从重新设计 AppComponent
模板,即“app.component.html”开始。我们需要另外两个按钮,“Add New”和“Cancel”。
这是完整的 HTML。
<h1>Employee</h1>
<div [hidden]="IsAddNew">
<input type="button" value="Add New" (click)="ShowAddNew()">
<table border="1">
<tr>
<th>Emp Name</th>
<th>Salary </th>
</tr>
<tr *ngFor="let emp of Employees">
<td>{{emp.FName}} {{emp.LName}}</td>
<td>{{emp.Salary}}</td>
</tr>
</table>
</div>
<div [hidden]="!IsAddNew">
FName: <input type="text"><br>
LName: <input type="text"><br>
Salary: <input type="text"><br>
<input type="button" value="Save" (click)="SaveEmployee()">
<input type="button" value="Cancel" (click)="HideAddNew()">
</div>
您可以看到“IsAddNew
”变量通过属性绑定到“hidden
”属性。
不要错过第二个 div
中使用的“!
”符号与“IsAddNew
”。这意味着“hidden
”将绑定到“IsAddNew
”的相反值。换句话说,当“IsAddNew
”不为 true
时,第二个“div
”将隐藏/不可见。如果“IsAddNew
”为 true
,它将显示。
步骤 2 – 在组件类中实现逻辑
在“app.component.ts”文件中实现以下更改。
...
…
export class AppComponent{
Employees:Array<Employee>;
IsAddNew:boolean;
constructor(){
this.IsAddNew=false;
this.Employees =new Array<Employee>();
...
...
}
SaveEmployee():void{
...
...
this.IsAddNew=false;
}
ShowAddNew():void{
this.IsAddNew=true;
}
HideAddNew():void{
this.IsAddNew=false;
}
}
步骤 3 – 编译并测试输出
打开浏览器。您将看到以下输出
总结
至此,我们完成了第 3 天的内容。
目前,我们的应用程序只是一个大的 UI。我们有一个组件,仅此而已。我们肯定没有遵循面向组件的风格。下次,我们将把我们的应用程序分解成多个小型、可重用、有意义且可组合的 Web 组件。
在第 4 天,我们还将学习如何创建自定义输入/输出属性以及如何在 Angular 中处理输入控件。在此之前,祝您编码愉快,敬请关注。
历史
- 2017年8月9日:初始版本