框架之间的前端现在有三个不同的领导者:Angular,React和Vue。我认为我们可以通过GitHub上的星星数来判断开发人员对该项目的热爱。在撰写本文时,Vue已经拥有16.1万颗恒星,React和14.6万颗排名第二,而Angular及其适度的5.96万颗排名第三。
乍一看,Angular似乎不像其他框架那样受欢迎,但是如果我们看一下Tecla门户网站的统计研究结果,就会发现Angular占据了相当大的市场份额。例如,根据一项研究,Angular在40万个站点上运行,而Vue在10万个站点上运行。我建议对此进行解决。考虑一下为什么开发人员喜欢Vue,为什么许多应用程序是用Angular编写的,以及开发人员在专门为自己使用Google的框架时可以获得什么好处。

关于爱情
大多数情况下,Vue的特殊便利性突出显示了以下各项(未按优先级顺序列出):
- 低门槛
- 捆束尺寸
- 性能
- 单个文件组件
- 简单的模板语法
- 使用插件和模块轻松扩展
- DOM
- Vue CLI
, — Developer Experience, . , . , , vue-cli
, , , , .
Vue — , Angular ? — , , Vue. , API, . .
, . Angular , - / . .
SPA- API. ?
- Vue: .
fetch
axios
- ? ? ? ? — . — . , . - Angular: Angular
HttpClient
, , . , Angular CLI. Interceptor
. , , .
, Angular , , , . , , 100% Vue.
, — , - ( ). , Angular .
, API. .
" " Vue . , , . ? ? , "" ? , Vuelidate
. , .
Angular “ ” . FormGroup
, , … . . , dirty
. -.
Dependency Injection
DI — , . , Angular .
, , . , API . Angular , UserService
. .
Vue:
Angular:
Angular , UserService
. , , . , .
, DI. . , , . , .
CLI
CLI — , - . , . Vue CLI , , , . . Vue , CLI .
Angular CLI , , , , . , .
-. -. , , . .
Angular CLI , . , .
, -. Vue — , .
Angular , , . , .
TypeScript
TypeScript — , "JavaScript that scales", . JavaScript , , "" . JavaScript .
Angular TypeScript , JavaScript . TypeScript, . , , .
Vue TypeScript. , Vue CLI TypeScript . , . , , . . , TypeScript .
Router
SPA- Lazy Loading'. Webpack', , . .
Vue Vue Router. , , Vue. Vue Router , , .
Angular RouterModule
, , ( , 16), . , .
Observable
Vue data
. render()
- . ?
— . — Observer
, "". , , - . , "" . - .
Angular , . RxJS
, . . , — , .
, Vue, Angular:
Vue Angular.
Vue
. , , , — , .
<script>
export default {
name: 'HelloHabr',
props: {
name: {
type: String,
required: true,
validator: value => value.trim().length !== 0,
},
},
data() {
return {
clickCount: 0,
secondsCount: 0,
intervalId: null,
};
},
computed: {
clicksPerSecond() {
if (this.secondsCount === 0) {
return 0;
}
const DECIMAL = 1000;
const ratio = this.clickCount / this.secondsCount;
return Math.round(ratio * DECIMAL) / DECIMAL;
},
},
created() {
this.intervalId = setInterval(() => {
this.secondsCount++;
}, 1000);
},
beforeDestroy() {
clearInterval(this.intervalId);
},
methods: {
countUp() {
this.$emit('updateClick', ++this.clickCount);
},
},
};
</script>
<template>
<div class="hello">
<p>, ! {{ name }}.</p>
<div class="click-place" :class="{ clicked: clickCount > 0 }">
<button @click="countUp()"> !</button>
<p v-if="clickCount > 0"> : {{ clickCount }}</p>
<p v-else> </p>
</div>
<div class="statistic">
<p> {{ secondsCount }} .</p>
<p> : {{ clicksPerSecond }}</p>
</div>
</div>
</template>
, , .
, :
<script>
import HelloHabr from './components/HelloHabr.vue';
export default {
name: 'App',
components: { HelloHabr }
...
};
</script>
:
<template>
<div id="app">
<HelloHabr :name="name" @updateClick="updateClickCount" />
</div>
</template>
Angular .
Angular
:
import {
Component,
EventEmitter,
Input,
OnDestroy,
OnInit,
Output,
} from '@angular/core';
@Component({
selector: 'hello-habr',
templateUrl: './hello-habr.component.html',
styleUrls: ['./hello-habr.component.less'],
})
export class HelloHabrComponent implements OnInit, OnDestroy {
@Input() name: string;
@Output() updateClick = new EventEmitter<number>();
clickCount = 0;
secondsCount = 0;
intervalId = null;
ngOnInit() {
this.intervalId = setInterval(() => {
this.secondsCount++;
}, 1000);
}
ngOnDestroy() {
clearInterval(this.intervalId);
}
get clicksPerSecond(): number {
if (this.secondsCount === 0) {
return 0;
}
const DECIMAL = 1000;
const ratio = this.clickCount / this.secondsCount;
return Math.round(ratio * DECIMAL) / DECIMAL;
}
countUp() {
this.updateClick.emit(++this.clickCount);
}
}
:
<p>, ! {{ name }}.</p>
<div class="click-place" [class.clicked]="clickCount > 0">
<button (click)="countUp()"> !</button>
<p *ngIf="clickCount > 0; else elseBlock">
: {{ clickCount }}
</p>
<ng-template #elseBlock><p> </p></ng-template>
</div>
<div class="statistic">
<p> {{ secondsCount }} .</p>
<p> : {{ clicksPerSecond }}</p>
</div>
, . Angular -. , . , . , , Vue.
Angular . , . , :
import { NgModule } from '@angular/core';
import { AppComponent } from './app.component';
import { HelloHabrComponent } from './hello-habr/hello-habr.component';
@NgModule({
declarations: [AppComponent, HelloHabrComponent],
imports: [BrowserModule],
providers: [],
bootstrap: [AppComponent],
})
export class AppModule {}
, , . AppComponent
.
. , . AppModule
, . , . :
import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { HelloHabrComponent } from './hello-habr.component';
@NgModule({
declarations: [HelloHabrComponent],
imports: [CommonModule],
exports: [HelloHabrComponent],
})
export class HelloHabrModule {}
, , , :
import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { AppComponent } from './app.component';
import { HelloHabrModule } from './hello-habr/hello-habr.module';
@NgModule({
declarations: [AppComponent],
imports: [BrowserModule, HelloHabrModule],
providers: [],
bootstrap: [AppComponent],
})
export class AppModule {}
. , Lazy-Loading'.
:
<hello-habr [name]="name" (updateClick)="updateClickCount($event)"></hello-habr>
, :
import { Component, EventEmitter, Input, Output } from '@angular/core';
import { BehaviorSubject, combineLatest, interval } from 'rxjs';
import { map, startWith } from 'rxjs/operators';
@Component({
selector: 'hello-habr',
templateUrl: './hello-habr.component.html',
styleUrls: ['./hello-habr.component.less'],
})
export class HelloHabrComponent {
@Input() name: string;
@Output() updateClick = new EventEmitter<number>();
clicksCount$ = new BehaviorSubject<number>(0);
secondsCount$ = interval(1000).pipe(
map(second => second++),
startWith(0)
);
clicksPerSecond$ = combineLatest(this.clicksCount$, this.secondsCount$).pipe(
map(([clicks, seconds]) => this.getClicksPerSecond(clicks, seconds))
);
countUp() {
const newValue = this.clicksCount$.value + 1;
this.updateClick.emit(newValue);
this.clicksCount$.next(newValue);
}
private getClicksPerSecond(
clicksCount: number,
secondsCount: number
): number {
if (secondsCount === 0) {
return 0;
}
const DECIMAL = 1000;
const ratio = clicksCount / secondsCount;
return Math.round(ratio * DECIMAL) / DECIMAL;
}
}
. :
- . Angular.
- .
- . . . , . , .
- , .
, . , , Angular:
- .
- : , , (interceptors), .
- CLI, , , .
- Dependency Injection — .
- RxJS TypeScript .
:
, , Vue. Angular 9 Ivy , , , . .