【Angular】提供给Vue用户的Angular教程
在学习框架时,我们会采取一种学习方法,就是类似于在Vue中该功能是如何实现的,那么在这个框架中又是如何实现的呢…
我最近正在学习Angular,整理了一些类似于Vue中的内容,并写了一篇文章。在与Vue进行比较的同时,我也介绍了Angular的基础知识。希望能对开始学习Angular的同伴们有所帮助!(^。^)
在这篇文章中介绍了React中“如同Vue中的…”的内容,请务必一起查看!✨
Angular 的定義是
如何启动Angular应用
请执行以下命令,以创建并运行Angular应用程序。
npm init @angular {アプリケーション名}
当你执行该命令时,会启动一个交互式命令行界面,要求你选择路由配置和样式语言。根据你想创建的应用程序的需求进行选择后,应用程序的创建将开始。
> ? Would you like to add Angular routing? (y/N)
> ? Which stylesheet format would you like to use? (Use arrow keys)
❯ CSS
SCSS [ https://sass-lang.com/documentation/syntax#scss ]
Sass [ https://sass-lang.com/documentation/syntax#the-indented-syntax ]
Less [ http://lesscss.org
如果你看到下面的输出,表示应用程序已经成功创建。如果出现“command not found: npm”错误,这意味着你的执行环境中没有安装Node.js和npm。请参考这篇文章进行安装后,再次执行下面的命令。
...
CREATE my-first-app/src/app/app.module.ts (393 bytes)
CREATE my-first-app/src/app/app.component.css (0 bytes)
CREATE my-first-app/src/app/app.component.html (23115 bytes)
CREATE my-first-app/src/app/app.component.spec.ts (1091 bytes)
CREATE my-first-app/src/app/app.component.ts (216 bytes)
✔ Packages installed successfully.
Successfully initialized git.
请在安装完成后,转到创建的应用程序目录。
cd {アプリケーション名}
当执行以下命令时,Angular开发服务器将在localhost:4200上启动(如果端口4200已被占用,则会使用其他端口)。
npm start
> my-first-app@0.0.0 start
> ng serve
✔ Browser application bundle generation complete.
Initial Chunk Files | Names | Raw Size
vendor.js | vendor | 2.04 MB |
polyfills.js | polyfills | 314.28 kB |
styles.css, styles.js | styles | 209.41 kB |
main.js | main | 48.10 kB |
runtime.js | runtime | 6.52 kB |
| Initial Total | 2.60 MB
Build at: 2023-05-03T05:01:09.540Z - Hash: d570b7afea270a79 - Time: 4150ms
** Angular Live Development Server is listening on localhost:4200, open your browser on http://localhost:4200/ **
✔ Compiled successfully.
同样,通过使用AngularCLI工具,可以让Angular应用开发更加轻松愉快。我建议您进行安装。有关AngularCLI的详细说明,请参阅此处的官方文档。
npm install -g @angular/cli
组件基础
在Angular中,一个组件由TypeScript文件,HTML文件和CSS文件组成。在Vue中,模板标签、脚本标签和样式标签分别存在于不同的文件中。听起来有点麻烦,但是通过使用AngularCLI,可以轻松创建组件。
请在应用程序的目录中执行以下命令。
ng generate component {コンポーネント名}
只要输出以下内容,就表示组件的自动生成已经完成。在创建组件时,需要在app.module.ts中注册组件,但这也会自动进行修正。非常方便。
CREATE src/app/hello/hello.component.css (0 bytes)
CREATE src/app/hello/hello.component.html (30 bytes)
CREATE src/app/hello/hello.component.spec.ts (656 bytes)
CREATE src/app/hello/hello.component.ts (237 bytes)
UPDATE src/app/app.module.ts (509 bytes)
此外,使用上述命令还会生成spec文件。由于这是用于测试实现的文件,请根据需要进行生成。你可以通过添加–skip-tests选项来阻止生成spec文件。
ng generate component {コンポーネント名} --skip-tests
Angular中,我写到了一个组件由一个TypeScript文件、一个HTML文件和一个CSS文件组成,但是在TypeScript文件中也可以表示模板。由于本文主要介绍如何将文件分开,所以请理解。
import { Component } from '@angular/core';
@Component({
selector: 'app-hello',
template: `
<h1>Hello Component</h1>
`,
styleUrls: ['./hello.component.css'],
})
export class HelloComponent {
}
在Vue中,所指的”data”
在TypeScript文件的组件类中,通过将其定义为成员变量,可以实现与data相同的功能。
import { Component } from '@angular/core';
@Component({
selector: 'app-hello',
templateUrl: './hello.component.html',
styleUrls: ['./hello.component.css'],
})
export class HelloComponent {
message = 'Hello World!';
flag = false;
}
在使用组件时,请按照以下方式使用。
<p *ngIf="flag">{{ message }}</p>
在Vue中所说的methods
在TypeScript文件中的组件类中,通过定义方法来实现与methods相同的功能。
当在方法内部访问成员变量(data)时,要像Vue一样使用this.{要访问的数据}进行编写。
import { Component } from '@angular/core';
@Component({
selector: 'app-hello',
templateUrl: './hello.component.html',
styleUrls: ['./hello.component.css'],
})
export class HelloComponent {
message = 'Hello World!';
helloWorld(): void {
alert(this.message);
}
saySomething(something: string): void {
alert(something);
}
}
在使用HTML文件中的方法时,请按照以下方式进行描述。
<button (click)="helloWorld()">HelloWorld!</button>
<button (click)="saySomething('Something!!')">SaySomething!</button>
在Vue中所指的computed
在Angular中,通常会介绍使用带有get关键字并定义getter方法来模拟Vue的computed属性。但在下面的情况中,在控制台中会多次输出“numberToDisplay called.”,即使返回值相同,也反复进行重新计算。Vue的computed属性具有缓存功能。如果在Vue中进行如下实现,则只会在控制台中输出一次,并且在依赖数据不发生变化的情况下不会再次进行计算。(在这篇文章中对computed属性的缓存功能进行了清晰明了的解释!)因此,使用带有get关键字的getter方法来模拟computed属性并不能产生适当的效果。根据我的调查,似乎没有找到一种能够复制缓存行为的方法,如果有了解的人,请务必留下评论。
import { Component } from '@angular/core';
@Component({
selector: 'app-user',
template: `
<p>{{ numberToDisplay }}</p>
<p>{{ numberToDisplay }}</p>
<p>{{ numberToDisplay }}</p>
<p>{{ numberToDisplay }}</p>
`,
styleUrls: ['./user.component.css'],
})
export class UserComponent {
number: number = 0;
get numberToDisplay(): number {
console.log('numberToDisplay called.');
return this.number + 1;
}
}
在Vue中,所谓的props
通过使用@Input装饰器,可以将数据从父组件传递给子组件。在下面的例子中,我们定义了一个名为name的属性并将值”Test props”从父组件传递给子组件。
import { Component, Input } from '@angular/core';
@Component({
selector: 'app-child',
templateUrl: './child.component.html',
styleUrls: ['./child.component.css']
})
export class ChildComponent {
@Input() name: string = '';
}
<p>{{ language }}</p> <!-- Test props -->
<app-child name="Test props"></app-child>
此外,如果要将变量绑定到子组件的传值中,则需要使用方括号[]将属性名称包围起来,如下所示。
<app-child [language]="propToChild"></app-child>
import { Component } from '@angular/core';
@Component({
selector: 'app-hello',
templateUrl: './hello.component.html',
styleUrls: ['./hello.component.css'],
})
export class HelloComponent {
propToChild = 'Hello';
}
在Vue中,所谓的emit
通过使用@Output装饰器和EventEmitter类,可以定义自定义事件(emit)。在下面的例子中,我们定义了一个名为“close”的自定义事件,并在子组件的按钮被点击时触发了该事件。你可以使用this.{eventName}.emit()来触发已定义的事件。
<button (click)="onClickClose()">Close</button>
import {
Component,
EventEmitter,
Output
} from '@angular/core';
@Component({
selector: 'app-child',
templateUrl: './child.component.html',
styleUrls: ['./child.component.css'],
})
export class ChildComponent {
@Output() close = new EventEmitter<any>();
onClickClose(): void {
this.close.emit();
}
}
<app-child language="propToChild" (close)="onEmitClose()"></app-child>
import { Component } from '@angular/core';
@Component({
selector: 'app-hello',
templateUrl: './hello.component.html',
styleUrls: ['./hello.component.css'],
})
export class HelloComponent {
onEmitClose(): void {
alert('Emitted!!!');
}
}
在事件触发时传递参数值的实现方式如下。
<button (click)="onClickClose(args)">Close</button>
import {
Component,
EventEmitter,
Output
} from '@angular/core';
@Component({
selector: 'app-child',
templateUrl: './child.component.html',
styleUrls: ['./child.component.css'],
})
export class ChildComponent {
@Output() close = new EventEmitter<string>();
onClickClose(): void {
this.close.emit('Hello');
}
}
<app-child language="propToChild" (close)="onEmitClose($event)"></app-child>
import { Component } from '@angular/core';
@Component({
selector: 'app-hello',
templateUrl: './hello.component.html',
styleUrls: ['./hello.component.css'],
})
export class HelloComponent {
onEmitClose(args): void {
alert(args);
}
}
在Vue中,可以理解为watch。
在Angular中,似乎没有检测到以成员变量的方式定义的值(相当于Vue中的data)的更改的方法(如果有的话,请务必告诉我)。然而,可以通过使用ngOnChanges()方法和@Input()从父组件接收的值(相当于Vue中的props)来检测变化。
要使用ngOnChanges()方法,需要实现OnChange接口。
import { Component, Input, OnChanges, SimpleChanges } from '@angular/core';
@Component({
selector: 'app-hello',
templateUrl: './hello.component.html',
styleUrls: ['./hello.component.css'],
})
export class HelloComponent implements OnChanges {
@Input() name = '';
ngOnChanges(changes: SimpleChanges): void {
console.error('Changed:', changes);
}
}
<p>Name: {{ name }}</p>
import { Component } from '@angular/core';
@Component({
selector: 'app-user',
templateUrl: './user.component.html',
styleUrls: ['./user.component.css']
})
export class UserComponent {
parentName: string = '';
}
Name: <input type="text" [(ngModel)]="parentName"/>
<app-hello [name]="parentName"></app-hello>
ngOnChanges()方法接收一个名为SimpleChanges对象的参数。您可以通过这个对象获取每个属性的旧值(previousValue)和新值(currentValue)。ngOnChanges()方法在@Input()属性初始化时也会执行,因此它在组件初始化时一定会执行一次。这时,firstChange属性会被设为true。
{
"name": {
"previousValue": "a",
"currentValue": "aa",
"firstChange": false
}
}
在Vue中所说的components
在Vue中,通常我们会在每个组件的components选项中添加要使用的子组件,而在Angular中,通常会在app.module.ts文件中指定要使用的组件,以便可以从所有组件中使用所有组件。
在@NgModule()装饰器的declarations选项中添加导入的类,即可完成组件的注册。
import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { AppRoutingModule } from './app-routing.module';
import { AppComponent } from './app.component';
import { HelloComponent } from './hello/hello.component';
import { RouterModule } from '@angular/router';
import { FormsModule } from '@angular/forms';
import { UserComponent } from './user/user.component';
import { ChildComponent } from './child/child.component';
import { ParentComponent } from './parent/parent.component';
import { TestComponent } from './test/test.component';
@NgModule({
declarations: [
AppComponent,
HelloComponent,
UserComponent,
ChildComponent,
ParentComponent,
TestComponent,
],
imports: [
BrowserModule,
AppRoutingModule,
FormsModule,
RouterModule.forRoot([]),
],
providers: [],
bootstrap: [AppComponent]
})
export class AppModule { }
指令
在Vue中,与@click相对应的是
使用click事件可以定义当元素被点击时要触发的事件。使用的形式是(click)=”触发的事件”。以下示例中,当按钮被点击时,执行了方法hello。
<button (click)="hello()">
Button
</button>
在Vue中,当写成@click=”hello”时,事件对象将作为方法的参数传递,但在Angular中,需要明确地将$event作为参数传递,如下所示。
<button (click)="hello($event)">
Button
</button>
在Vue中,相当于v-model
使用ngModel可以将变量绑定到表单的输入上。您可以像这样使用[(ngModel)]=”要绑定的变量”。下面的例子中,我们将变量name绑定到文本表单上。
<input type="text" [(ngModel)]="name" />
使用ngModel时,需要在app.module.ts中定义FormsModule如下。如果不定义,将会输出错误信息: Can’t bind to ‘ngModel’ since it isn’t a known property of ‘input’。
import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { AppComponent } from './app.component';
import { HelloComponent } from './hello/hello.component';
import { FormsModule } from '@angular/forms';
@NgModule({
declarations: [
AppComponent,
HelloComponent,
],
imports: [
BrowserModule,
FormsModule
],
providers: [],
bootstrap: [AppComponent]
})
export class AppModule { }
在Vue中被称为v-for
通过使用ngFor来表示循环。可以使用*ngFor=”let element of loopObj”这样的形式来使用。以下代码中,将显示带有ngFor的元素的次数为someArr的元素数量。
<div *ngFor="let item of someArr">
{{ item }}
</div>
在Vue中可以使用v-if
通过使用ngIf,可以根据条件来决定元素的显示。使用形式为*ngIf=”条件”。下面的示例中,如果isAngular为true,则会显示具有ngIf条件的元素以下内容。
<div *ngIf="isAngular">
<p>Hello Angular!</p>
</div>
在Vue中的说法是created/mounted
使用ngOnInit()能够在组件初始化时挂钩并执行一次处理。
要使用ngOnInit(),需要在组件类中实现OnInit接口。通过实现该接口,可以使用ngOnInit()方法。
import { Component, OnInit } from '@angular/core';
import axios from 'axios';
@Component({
selector: 'app-hello',
templateUrl: './hello.component.html',
styleUrls: ['./hello.component.css'],
})
export class HelloComponent implements OnInit {
users = [];
ngOnInit(): void {
this.getUsers();
}
async getUsers(): Promise<void> {
try {
const { data } = await axios.get('/api/users');
console.log(data);
} catch (e) {
console.error(e);
}
}
}
请参考官方文档以了解有关生命周期挂钩的信息。
路由(相当于Vue中的VueRouter)
最初的设置
在Vue中,我们需要安装VueRouter来进行路由操作,而在Angular中,我们可以进行路由操作而无需安装额外的软件包。在这里,我们将介绍路由引入的代表例。
请将RouterModule.forRoot()添加到app.module.ts文件的@NgModule()装饰器的imports中。
import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { AppComponent } from './app.component';
import { RouterModule } from '@angular/router';
@NgModule({
declarations: [
AppComponent,
],
imports: [
BrowserModule,
RouterModule.forRoot([])
],
providers: [],
bootstrap: [AppComponent]
})
export class AppModule { }
接下来,在src/app/app.component.html文件中添加 router-outlet 标签(就像Vue Router中的 router-view 一样)。
<router-outlet></router-outlet>
只需将路由信息作为数组形式添加到RouterModule.forRoot()的参数中,路由设置就完成了。路由信息应指定一个包含路径(path)和要显示的组件(component)的对象,具体如下所示。
import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { AppComponent } from './app.component';
import { RouterModule } from '@angular/router';
import { HelloComponent } from './hello/hello.component';
@NgModule({
declarations: [
AppComponent,
HelloComponent
],
imports: [
BrowserModule,
RouterModule.forRoot([
{
path: 'hello',
component: HelloComponent
}
])
],
providers: [],
bootstrap: [AppComponent]
})
export class AppModule { }
另外,如果要指定路由器的路径参数,可以在路径中使用:paramName的形式进行指定。
{
path: 'users/:userId',
component: UserComponent
}
搬迁
在Vue中,相当于
在Angular中,没有像VueRouter的标签那样的准备。相反,路由指令会添加到a标签上。要指定转换到的目标,请使用routerLink。您可以将定义的路径(在路由定义时指定的路径)指定为routerLink的值,从而可以转到相应的屏幕。
<a routerLink="/users">Users</a>
如果要指定路径参数,可以使用链接参数数组。通过将routerLink括在[]中,可以将数组值指定为链接的值。将导航目标的路径放在数组的第一个元素中,将路径参数放在第二个元素中。在以下情况下,导航目标的URL将是”/users/1″。
<a [routerLink]="['/users', 1]">Users</a>
在Vue中,相当于this.$router.push()的是什么?
在 TypeScript 中进行页面导航时,我们使用 navigate() 方法。我们需要将 navigate() 的参数设置为与 routerLink 指定的内容相同的值。
import { Component } from '@angular/core';
import { Router } from '@angular/router';
@Component({
selector: 'app-hello',
templateUrl: './hello.component.html',
styleUrls: ['./hello.component.css'],
})
export class HelloComponent {
constructor(private _router: Router) {}
jumpToUserPage(): void {
this._router.navigate(['/users', 1]);
}
}