Vue开发人员的Angular

框架之间的前端现在有三个不同的领导者: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:


  • " "
  • Angular
  • CLI


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);
  }

  // ,    
  //      Vue,   
  //    
  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>

<!--  Angular      -->
<div class="click-place" [class.clicked]="clickCount > 0">
  <!--     ,     -->
  <button (click)="countUp()"> !</button>

  <!-- ,   DOM-    -->
  <!-- else-      -->
  <p *ngIf="clickCount > 0; else elseBlock">
      : {{ clickCount }}
  </p>
  <!--  else-    -->
  <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],
  // CommonModule     *ngIf
  imports: [CommonModule],
  //      HelloHabrModule
  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],
  //      "HelloHabrComponent"
  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 .

:


  • .
  • .
  • Angular .

, , Vue. Angular 9 Ivy , , , . .


All Articles