创建你的第一个Angular项目
环境准备
在开始创建 Angular 项目之前,确保你已经安装了以下工具:
- Node.js:Angular 项目依赖于 Node.js 运行时环境,你可以从Node.js 官方网站下载并安装最新的 LTS(长期支持)版本。安装完成后,在命令行中输入
node -v
和npm -v
来验证安装是否成功,它们会分别输出版本号。 - Angular CLI:Angular CLI(命令行界面)是用于初始化、开发和维护 Angular 项目的核心工具。通过 npm(Node 包管理器,随 Node.js 一同安装)全局安装 Angular CLI,在命令行中执行以下命令:
npm install -g @angular/cli
安装完成后,输入 ng --version
验证 Angular CLI 是否安装成功并查看其版本号。
创建新项目
一切准备就绪后,就可以开始创建第一个 Angular 项目了。打开命令行终端,导航到你想要创建项目的目录,例如:
cd C:\projects
然后,使用 Angular CLI 创建一个新的 Angular 项目,执行以下命令:
ng new my - first - angular - project
这里,my - first - angular - project
是项目的名称,你可以根据自己的喜好替换。在创建过程中,Angular CLI 会询问你一些问题:
- 是否使用 Angular routing:路由用于在单页应用中实现页面导航。如果你的应用需要多个页面之间进行导航,输入
y
;如果是简单的单页面应用,输入n
。例如,对于一个简单的展示型应用,可能不需要路由,此时输入n
。 - 选择 CSS 预处理器:Angular CLI 支持多种 CSS 预处理器,如 Sass、Less 和 Stylus。如果你对预处理器不熟悉,选择默认的 CSS 即可。如果选择 Sass,它会在项目中配置 Sass 相关的设置,方便你使用 Sass 的特性,如变量、嵌套等。
项目结构剖析
创建好项目后,进入项目目录:
cd my - first - angular - project
使用你喜欢的代码编辑器(如 Visual Studio Code)打开项目,此时可以看到项目的目录结构,以下是一些主要目录和文件的介绍:
src
目录:这是项目的核心源代码目录,所有与应用相关的代码都在这里编写。app
目录:存放应用的组件、服务、模块等核心代码。一个典型的 Angular 应用由多个组件组成,每个组件都有自己的逻辑和视图。assets
目录:用于存放静态资源,如图像、字体、配置文件等。例如,你可以将项目中使用的 logo 图片放在这个目录下,然后在组件中通过相对路径引用。environments
目录:包含不同环境的配置文件,如environment.ts
用于开发环境,environment.prod.ts
用于生产环境。这些文件可以用于配置 API 端点等在不同环境下可能变化的参数。
angular.json
文件:这是项目的配置文件,包含了项目的构建、测试、部署等各种配置选项。例如,你可以在这里配置项目的输出路径、启用或禁用特定的构建优化等。package.json
文件:记录了项目的依赖项以及一些脚本命令。当你使用npm install
安装新的包时,相关信息会自动更新到这个文件中。同时,你可以在scripts
字段中定义自定义的脚本命令,方便执行一些特定的任务。
运行项目
在项目目录下,通过以下命令启动 Angular 开发服务器:
ng serve
该命令会编译项目并启动一个本地服务器,默认情况下,应用会在 http://localhost:4200
上运行。你可以在浏览器中打开这个地址,就能看到默认的 Angular 欢迎页面。在开发过程中,Angular CLI 会监控文件的变化,当你修改了源代码,服务器会自动重新编译并刷新页面,方便你实时查看更改效果。
创建第一个组件
组件是 Angular 应用的基本构建块,它包含了视图(HTML)、逻辑(TypeScript)和样式(CSS)。使用 Angular CLI 创建一个新的组件非常简单,在项目目录下执行以下命令:
ng generate component my - first - component
这会在 src/app
目录下创建一个名为 my - first - component
的新组件,同时生成以下文件:
my - first - component.component.ts
:这是组件的逻辑文件,使用 TypeScript 编写。以下是一个简单的示例:
import { Component } from '@angular/core';
@Component({
selector: 'app - my - first - component',
templateUrl: './my - first - component.component.html',
styleUrls: ['./my - first - component.component.css']
})
export class MyFirstComponentComponent {
message: string = 'Hello, Angular!';
}
在这个组件类中,我们定义了一个 message
属性,它是一个字符串类型,值为 Hello, Angular!
。@Component
装饰器用于配置组件,selector
定义了组件在 HTML 中的标签名,templateUrl
指向组件的视图模板文件,styleUrls
指向组件的样式文件。
2. my - first - component.component.html
:这是组件的视图模板文件,使用 HTML 编写。在这个文件中,我们可以使用 Angular 的模板语法来展示数据和定义交互。例如:
<div>
<h1>{{message}}</h1>
</div>
这里使用了双花括号 {{}}
来插值表达式,将组件类中的 message
属性的值显示在页面上。
3. my - first - component.component.css
:这是组件的样式文件,用于定义组件的样式。例如,我们可以为上面的 h1
标签添加一些样式:
h1 {
color: blue;
}
在应用中使用组件
要在整个应用中使用我们刚刚创建的组件,需要将其添加到应用的主组件模板中。打开 src/app/app.component.html
文件,将以下代码添加进去:
<app - my - first - component></app - my - first - component>
保存文件后,刷新浏览器,你会看到页面上显示出蓝色的 Hello, Angular!
,这表明我们的组件已经成功在应用中使用。
数据绑定
数据绑定是 Angular 中的一个重要概念,它允许在组件的视图和逻辑之间建立联系。Angular 支持以下几种数据绑定方式:
- 插值绑定:如前面在
my - first - component.component.html
中使用的{{message}}
,它将组件类中的属性值插入到视图中。 - 属性绑定:用于设置 HTML 元素的属性值。例如,在
my - first - component.component.html
中添加一个图片标签,并通过属性绑定设置其src
属性:
<div>
<h1>{{message}}</h1>
<img [src]="imageUrl" alt="My Image">
</div>
然后在 my - first - component.component.ts
中添加 imageUrl
属性:
import { Component } from '@angular/core';
@Component({
selector: 'app - my - first - component',
templateUrl: './my - first - component.component.html',
styleUrls: ['./my - first - component.component.css']
})
export class MyFirstComponentComponent {
message: string = 'Hello, Angular!';
imageUrl: string = 'assets/logo.png';
}
这样,图片就会根据 imageUrl
的值进行显示。这里的 [src]
就是属性绑定的语法,方括号将属性名括起来。
3. 事件绑定:用于监听 HTML 元素的事件。例如,添加一个按钮,并监听其点击事件:
<div>
<h1>{{message}}</h1>
<img [src]="imageUrl" alt="My Image">
<button (click)="onButtonClick()">Click Me</button>
</div>
在 my - first - component.component.ts
中添加 onButtonClick
方法:
import { Component } from '@angular/core';
@Component({
selector: 'app - my - first - component',
templateUrl: './my - first - component.component.html',
styleUrls: ['./my - first - component.component.css']
})
export class MyFirstComponentComponent {
message: string = 'Hello, Angular!';
imageUrl: string = 'assets/logo.png';
onButtonClick() {
this.message = 'Button Clicked!';
}
}
当点击按钮时,onButtonClick
方法会被调用,从而更新 message
属性的值,视图也会随之更新。这里的 (click)
就是事件绑定的语法,圆括号将事件名括起来。
4. 双向数据绑定:在表单元素中经常使用,它结合了属性绑定和事件绑定,使得视图和模型之间的数据能够实时同步。例如,创建一个输入框,并实现双向数据绑定:
首先,在 my - first - component.component.html
中添加输入框:
<div>
<h1>{{message}}</h1>
<img [src]="imageUrl" alt="My Image">
<button (click)="onButtonClick()">Click Me</button>
<input [(ngModel)]="message" type="text">
</div>
然后,需要在 my - first - component.component.ts
所在的模块中导入 FormsModule
。打开 src/app/app.module.ts
文件,添加以下导入和配置:
import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform - browser';
import { FormsModule } from '@angular/forms';
import { AppComponent } from './app.component';
import { MyFirstComponentComponent } from './my - first - component/my - first - component.component';
@NgModule({
declarations: [
AppComponent,
MyFirstComponentComponent
],
imports: [
BrowserModule,
FormsModule
],
providers: [],
bootstrap: [AppComponent]
})
export class AppModule {}
这样,当在输入框中输入内容时,message
属性的值会实时更新,同时视图上显示的 message
也会实时变化。这里的 [(ngModel)]
就是双向数据绑定的语法,它是 [ngModel]
(属性绑定)和 (ngModelChange)
(事件绑定)的组合。
组件交互
在一个复杂的 Angular 应用中,组件之间通常需要进行交互。以下是几种常见的组件交互方式:
- 父子组件交互:
- 父组件向子组件传递数据:通过输入属性实现。首先,在子组件
my - first - component.component.ts
中定义一个输入属性。修改my - first - component.component.ts
如下:
- 父组件向子组件传递数据:通过输入属性实现。首先,在子组件
import { Component, Input } from '@angular/core';
@Component({
selector: 'app - my - first - component',
templateUrl: './my - first - component.component.html',
styleUrls: ['./my - first - component.component.css']
})
export class MyFirstComponentComponent {
@Input() parentData: string;
}
然后在父组件 app.component.html
中使用子组件并传递数据:
<app - my - first - component [parentData]="parentMessage"></app - my - first - component>
在 app.component.ts
中定义 parentMessage
属性:
import { Component } from '@angular/core';
@Component({
selector: 'app - root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})
export class AppComponent {
parentMessage: string = 'Data from parent';
}
在子组件的视图 my - first - component.component.html
中可以显示这个数据:
<div>
<p>{{parentData}}</p>
</div>
- **子组件向父组件传递数据**:通过输出属性和事件发射器实现。在子组件 `my - first - component.component.ts` 中定义一个输出属性和一个方法来触发事件:
import { Component, Output, EventEmitter } from '@angular/core';
@Component({
selector: 'app - my - first - component',
templateUrl: './my - first - component.component.html',
styleUrls: ['./my - first - component.component.css']
})
export class MyFirstComponentComponent {
@Output() childEvent = new EventEmitter<string>();
sendDataToParent() {
this.childEvent.emit('Data from child');
}
}
在子组件的视图 my - first - component.component.html
中添加一个按钮来触发这个方法:
<div>
<button (click)="sendDataToParent()">Send Data to Parent</button>
</div>
在父组件 app.component.html
中监听子组件的事件:
<app - my - first - component (childEvent)="handleChildEvent($event)"></app - my - first - component>
在 app.component.ts
中定义 handleChildEvent
方法来处理接收到的数据:
import { Component } from '@angular/core';
@Component({
selector: 'app - root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})
export class AppComponent {
handleChildEvent(data: string) {
console.log('Received data from child:', data);
}
}
- 兄弟组件交互:通常通过一个共享服务来实现。首先,使用 Angular CLI 创建一个共享服务:
ng generate service shared
这会在 src/app
目录下生成 shared.service.ts
文件。修改 shared.service.ts
如下:
import { Injectable } from '@angular/core';
import { Subject } from 'rxjs';
@Injectable({
providedIn: 'root'
})
export class SharedService {
private messageSource = new Subject<string>();
message$ = this.messageSource.asObservable();
sendMessage(message: string) {
this.messageSource.next(message);
}
}
这个服务使用 RxJS 的 Subject
来创建一个可观察对象 message$
,并提供一个 sendMessage
方法来发送消息。
然后,在其中一个兄弟组件(假设为 brother - component - 1.component.ts
)中注入服务并发送消息:
import { Component } from '@angular/core';
import { SharedService } from '../shared.service';
@Component({
selector: 'app - brother - component - 1',
templateUrl: './brother - component - 1.component.html',
styleUrls: ['./brother - component - 1.component.css']
})
export class BrotherComponent1Component {
constructor(private sharedService: SharedService) {}
sendMessage() {
this.sharedService.sendMessage('Message from brother 1');
}
}
在其视图 brother - component - 1.component.html
中添加一个按钮来触发发送消息的方法:
<div>
<button (click)="sendMessage()">Send Message to Brother 2</button>
</div>
在另一个兄弟组件 brother - component - 2.component.ts
中注入服务并订阅消息:
import { Component } from '@angular/core';
import { SharedService } from '../shared.service';
@Component({
selector: 'app - brother - component - 2',
templateUrl: './brother - component - 2.component.html',
styleUrls: ['./brother - component - 2.component.css']
})
export class BrotherComponent2Component {
receivedMessage: string;
constructor(private sharedService: SharedService) {
this.sharedService.message$.subscribe(message => {
this.receivedMessage = message;
});
}
}
在其视图 brother - component - 2.component.html
中显示接收到的消息:
<div>
<p>Received message: {{receivedMessage}}</p>
</div>
模块
模块是 Angular 应用中的一个重要概念,它将相关的组件、服务、指令等组织在一起,提高代码的可维护性和复用性。Angular 应用至少有一个根模块,通常是 AppModule
。在 src/app/app.module.ts
文件中,定义了 AppModule
:
import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform - browser';
import { AppComponent } from './app.component';
import { MyFirstComponentComponent } from './my - first - component/my - first - component.component';
@NgModule({
declarations: [
AppComponent,
MyFirstComponentComponent
],
imports: [
BrowserModule
],
providers: [],
bootstrap: [AppComponent]
})
export class AppModule {}
declarations
:用于声明本模块中拥有的视图类,包括组件、指令和管道。例如,我们将AppComponent
和MyFirstComponentComponent
声明在这里。imports
:用于导入本模块需要使用的其他模块。BrowserModule
是 Angular 应用在浏览器环境中运行所需的基础模块。providers
:用于注册服务,这些服务可以在整个应用中使用。如果一个服务在这里注册,它会被创建为单例,在应用的任何地方注入时都是同一个实例。bootstrap
:指定应用的主组件,这里是AppComponent
。当应用启动时,Angular 会首先渲染这个组件。
在大型应用中,通常会创建多个特性模块来组织不同功能的代码。例如,创建一个用户模块 UserModule
来管理与用户相关的组件、服务等。首先,使用 Angular CLI 创建模块:
ng generate module user
这会在 src/app
目录下生成 user.module.ts
文件。假设我们有一个 UserComponent
用于显示用户信息,在 user.module.ts
中配置如下:
import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { UserComponent } from './user.component';
@NgModule({
declarations: [
UserComponent
],
imports: [
CommonModule
],
providers: [],
exports: [UserComponent]
})
export class UserModule {}
这里导入了 CommonModule
,它包含了一些常用的指令和管道,如 NgIf
、NgFor
等。exports
数组用于指定哪些组件、指令或管道可以被其他模块使用。如果其他模块导入了 UserModule
,就可以使用 UserComponent
。
然后,在 AppModule
中导入 UserModule
:
import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform - browser';
import { AppComponent } from './app.component';
import { MyFirstComponentComponent } from './my - first - component/my - first - component.component';
import { UserModule } from './user.module';
@NgModule({
declarations: [
AppComponent,
MyFirstComponentComponent
],
imports: [
BrowserModule,
UserModule
],
providers: [],
bootstrap: [AppComponent]
})
export class AppModule {}
这样,就可以在 AppComponent
的视图中使用 UserComponent
了。
服务
服务是在 Angular 应用中用于处理一些通用逻辑的类,如数据获取、日志记录等。以数据获取为例,假设我们有一个 API 用于获取用户列表,创建一个服务来处理这个逻辑。首先,使用 Angular CLI 创建服务:
ng generate service user - data
这会在 src/app
目录下生成 user - data.service.ts
文件。修改 user - data.service.ts
如下:
import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { Observable } from 'rxjs';
@Injectable({
providedIn: 'root'
})
export class UserDataService {
private apiUrl = 'https://example.com/api/users';
constructor(private http: HttpClient) {}
getUsers(): Observable<any[]> {
return this.http.get<any[]>(this.apiUrl);
}
}
这里注入了 HttpClient
,它是 Angular 提供的用于处理 HTTP 请求的服务。getUsers
方法返回一个 Observable
,表示异步操作的结果,通过 http.get
方法从指定的 API 地址获取用户数据。
在组件中使用这个服务,例如在 UserComponent
中:
import { Component } from '@angular/core';
import { UserDataService } from '../user - data.service';
@Component({
selector: 'app - user - component',
templateUrl: './user - component.component.html',
styleUrls: ['./user - component.component.css']
})
export class UserComponent {
users: any[];
constructor(private userDataService: UserDataService) {}
ngOnInit() {
this.userDataService.getUsers().subscribe(data => {
this.users = data;
});
}
}
在 ngOnInit
生命周期钩子函数中,调用服务的 getUsers
方法,并通过 subscribe
方法处理获取到的数据,将其赋值给 users
属性,然后可以在视图中显示用户列表。
路由
路由允许在单页应用中实现页面导航,提供类似于多页应用的用户体验。假设我们的应用有两个页面,一个是首页,一个是关于页面。首先,在创建项目时如果选择了使用路由,Angular CLI 已经为我们生成了基本的路由配置文件 app - routing.module.ts
。如果没有选择,可以通过以下命令生成:
ng generate module app - routing --flat --module=app
--flat
选项表示将文件放在 src/app
目录下而不是创建一个新的 app - routing
目录,--module=app
表示将这个模块注册到 AppModule
中。
打开 app - routing.module.ts
文件,配置如下:
import { NgModule } from '@angular/core';
import { Routes, RouterModule } from '@angular/router';
import { HomeComponent } from './home.component';
import { AboutComponent } from './about.component';
const routes: Routes = [
{ path: '', component: HomeComponent },
{ path: 'about', component: AboutComponent }
];
@NgModule({
imports: [RouterModule.forRoot(routes)],
exports: [RouterModule]
})
export class AppRoutingModule {}
这里定义了两条路由,一条是空路径,对应首页组件 HomeComponent
;另一条是 about
路径,对应关于页面组件 AboutComponent
。
然后创建 HomeComponent
和 AboutComponent
:
ng generate component home
ng generate component about
在 HomeComponent
和 AboutComponent
的视图中添加一些内容,例如在 home.component.html
中:
<div>
<h1>Home Page</h1>
</div>
在 about.component.html
中:
<div>
<h1>About Page</h1>
</div>
在 app.component.html
中添加导航链接和路由出口:
<ul>
<li><a routerLink="">Home</a></li>
<li><a routerLink="about">About</a></li>
</ul>
<router - outlet></router - outlet>
routerLink
指令用于指定导航链接的路径,router - outlet
是路由出口,用于显示匹配路由的组件。
这样,当用户点击导航链接时,相应的组件会在路由出口中显示,实现页面导航功能。
总结与实践
通过以上步骤,我们完成了从创建 Angular 项目到构建一个具有基本功能的应用的过程,包括组件创建、数据绑定、组件交互、模块和服务的使用以及路由配置。在实际开发中,你可以根据项目需求进一步扩展和完善应用,例如添加更多的组件和功能,优化样式,处理更复杂的数据交互等。不断实践和学习,你将能够熟练掌握 Angular 开发技术,构建出高质量的前端应用。同时,要关注 Angular 的官方文档和社区资源,以获取最新的技术信息和最佳实践。