Руководство по использованию Angular7.0

внешний фреймворк

Цель этой статьи — быстро начать разработку под углом или быстро понять статьи, посвященные разработке под углом.

Строительство окружающей среды

  1. Установка строительных лесов: npm i -g @angular/cli
  2. Новый проект: ng new my-app

Если установочные леса сообщают об ошибке, принудительно очистите кеш npm и переустановите его.

Компоненты и шаблоны

После того, как вы скачаете официальный список программ, вы можете быть не знакомы с директорией, поэтому пока не зацикливайтесь на ней, статья посвящена тому, как быстро начать работу с angular проектом.

Понимание контекста выражения шаблона

Переменные контекста в выражениях состоят из следующих трех типов:

  1. Переменные шаблона (объект $event шаблона, входные переменные шаблона (let hero) и ссылочные переменные шаблона (#heroForm))
  2. Контекстные переменные для директив (атрибуты в директивах)
  3. Переменные-члены компонентов (столбцы экземпляра компонента)

При наличии одного и того же порядка приоритета переменных выражения: переменная шаблона >> переменная контекста директивы >> переменная-член компонента

import { Component } from '@angular/core';

//my-app/src/app/app.component.ts
@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css']
})
export class AppComponent {
  private data0:Number = 1121; 
  data1 = '<div>dddddd</div>';
  data2 = {
    aaa:222
  };
  data3(){
  };
  data4 = null;
  data5 = undefined;
  data6 = [1,2,3]
}
<div>
  <div>data0 :{{data0}}</div>
  <div>data1 :{{data1}}</div>
  <div>data2 :{{data2}}</div>
  <div>data3 :{{data3}}</div>
  <div>data4 :{{data4}}</div>
  <div>data5 :{{data5}}</div>
  <div>data6 :{{data6}}</div>
  <div>data7 :{{data7}}</div>
</div>

<!-- 
	data0 :1121
	data1 :<div>dddddd</div>
	data2 :[object Object]
	data3 :function () { }
	data4 :
	data5 :
	data6 :1,2,3
	data7 : 
-->

Понимание атрибутов HTML и свойств DOM

Давайте посмотрим на столбец

//html:<input type="text" value="a">
var outPutVal = function(){
    console.log('getAttribute:',inO.getAttribute('value'));
    console.log('inO.value:',inO.value);
}

window.onload = function(){
    var inO = document.querySelect('input');
    outPutVal(inO);
    //getAttribute: a
    //inO.value: a
    document.onclick = function(){
        //<input type="text" value="a"> 手动输入value为aaaaa后打印
        outPutVal(inO);
        //getAttribute: a
        //inO.value: aaaaa
    }
}

Приведенный выше нативный js показывает разницу между атрибутами HTML и свойствами DOM:

  1. Существует сопоставление 1:1 между несколькими атрибутами и свойствами HTML, такими как id.
  2. Некоторые атрибуты HTML не имеют соответствующих свойств, например colspan.
  3. Некоторые свойства DOM не имеют соответствующих атрибутов, например textContent.

Привязка шаблона Angular работает через свойства и события, а не атрибуты

привязка специального атрибута

[attr.aria-label]="actionName"
<td [attr.colspan]="1 + 1">

инструкция

Существует три типа команд:

  1. Компоненты — директивы с шаблонами
  2. Структурные директивы — директивы, которые изменяют макет DOM, добавляя и удаляя элементы DOM.
  3. Атрибутные директивы — директивы, которые изменяют внешний вид и поведение элементов, компонентов или других директив.

директива атрибута

  1. ngClass
  2. ngStyle
  3. ngModel

Структурные директивы

  1. ngIf
  2. ngFor
  3. ngSwitch
нг-шаблон * синтаксис
<div *ngIf="hero" class="name">{{hero.name}}</div>
-----------------------------------
<ng-template [ngIf]="hero">
  <div class="name">{{hero.name}}</div>
</ng-template>
<div *ngFor="let hero of heroes; let i=index; let odd=odd; trackBy: trackById" [class.odd]="odd">
  ({{i}}) {{hero.name}}
</div>
-----------------------------------
<ng-template ngFor let-hero [ngForOf]="heroes" let-i="index" let-odd="odd" [ngForTrackBy]="trackById">
  <div [class.odd]="odd">({{i}}) {{hero.name}}</div>
</ng-template>

Angular заменяет и его обернутое содержимое комментарием перед рендерингом представления.

ng-container

Сгруппируйте одноуровневые элементы вместе, а ng-template оборачивает внутренние элементы без побочных эффектов.

Что значит не иметь побочных эффектов? (Например: сломанная структура html!):

<p>
  I turned the corner
  <span *ngIf="hero">
    and saw {{hero.name}}. I waved
  </span>
  and continued on my way.
</p>

---------------------------

<p>
  I turned the corner
  <ng-container *ngIf="hero">
    and saw {{hero.name}}. I waved
  </ng-container>
  and continued on my way.
</p>

Компоненты -- специальные директивы (директивы с шаблонами)

ng g c components/A 创建组件

Несколько способов связи компонентов

1. Входное свойство @Input() (родительский компонент передает данные дочернему компоненту)
//a.component.ts
  @Input()
  inAttr:String;


  private _name:String = '';
----------------------------------------------------
  @Input()
  set inAttr2(name:String){
    this._name = name;
  }
  
  get inAttr2():String{
    return this._name;
  }
2. Выходное свойство @Output() (дочерние компоненты передают данные родительским компонентам)
//子组件中
@Output()
myEvent:EventEmitter<DataType> = new EventEmitter();

this.myEvent.emit(Data);

//父组件中
(myEvent)="myHandleEvent($event)"
myHandleEvent(Data:DataType){
    
}
3. Режим «человек посередине» (родственные компоненты передают значения через общий родительский компонент)
4. Родительский компонент получает ссылку на дочерний компонент #child (может использоваться только в шаблоне компонента)
5. Класс родительского компонента @ViewChild() вставляет дочерний компонент (используется в классе компонентов)
  1. Доступ к внедренным дочерним компонентам возможен только после того, как Angular покажет представление родительского компонента (доступ во время жизненного цикла ngAfterViewInit)
  2. Правило одностороннего потока данных Angular предотвращает обновление представлений родительских компонентов в одном и том же цикле. Приложение вынуждено ждать еще один раунд, прежде чем отображать секунды.
  3. Обходной путь: используйте setTimeout() для изменения данных
@ViewChild(ChildComponent)
private childComponent: ChildComponent;

ngAfterViewInit() {
    setTimeout(() => this.seconds = () => this.childComponent.changeData, 0);
}
6. Изменение данных через сервисы (используется в любой компонентной структуре)

пользовательская директива

ng g d myDirective/demo
  1. директива атрибута

ElementRef: оболочка вокруг нативного элемента в представлении.

import { Directive, ElementRef, HostListener, Input } from '@angular/core';

@Directive({
  selector: '[appDemo]'
})
export class DemoDirective {
  //构造函数要声明需要注入的元素 el: ElementRef。
  constructor(private el:ElementRef) { }
  // 注册事件
  @HostListener('click')
  show(){
    console.log(this.el.nativeElement);
    console.log(this.ss);
  }
  //指令参数,当参数名与指令名相同时,可以直接赋值给指令
  @Input()
  ss:String = 'aaa';
}

<button appDemo [ss]="bbb">click me</button>
  1. Структурные директивы

TemplateRef: получить содержимое

ViewContainerRef: доступ к контейнеру представления

import { Directive, Input, TemplateRef, ViewContainerRef } from '@angular/core';

@Directive({ selector: '[appUnless]'})
export class UnlessDirective {
  //第一次传入true时不执行任何if分支,提升性能
  private hasView = false;

  constructor(
    private templateRef: TemplateRef<any>,
    private viewContainer: ViewContainerRef) { }

  @Input() set appUnless(condition: boolean) {
    if (!condition && !this.hasView) {
      //实列化一个试图,并把它插入到该容器中
      this.viewContainer.createEmbeddedView(this.templateRef);
      this.hasView = true;
    } else if (condition && this.hasView) {
      this.viewContainer.clear();
      this.hasView = false;
    }
  }
}

трубопровод

Вы можете думать о конвейере как об операторе, который обрабатывает данные, а затем отображает их, например:

<p>{{ birthday}}</p>
<p>{{ birthday | date }}</p>
<!--链式调用管道-->
<p>{{ birthday | date | uppercase}}</p>

Встроенный конвейер Angular:

DatePipe, UpperCasePipe, LowerCasePipe, CurrencyPipe и PercentPipe.......

пользовательский конвейер

import { Pipe, PipeTransform } from '@angular/core';
@Pipe({name: 'exponentialStrength'})
export class ExponentialStrengthPipe implements PipeTransform {
  transform(value: number, exponent: string): number {
    let exp = parseFloat(exponent);
    return Math.pow(value, isNaN(exp) ? 1 : exp);
  }
}

Чистые и нечистые трубы

  1. Angular выполнит чистый канал только в том случае, если обнаружит чистое изменение входного значения. Чистые изменения — это изменения значений примитивного типа (String, Number, Boolean, Symbol) или изменения ссылок на объекты (Date, Array, Function, Object).

  2. Angular выполняет нечистую сантехнику во время цикла обнаружения изменений каждого компонента. Нечистые каналы могут вызываться столько раз, сколько раз нажимается клавиша или перемещается мышь.

@Pipe({
  name: 'flyingHeroesImpure',
  pure: false
})
export class FlyingHeroesImpurePipe extends FlyingHeroesPipe {}

внедрение зависимости

Внедрение зависимостей - это способ добиться инверсии управления, передав создание объектов, его преимущества могут быть отражены в фактической разработке, ниже он будет представлен

Способ реализации инверсии управления в Angular — это внедрение зависимостей.

Преимущества внедрения зависимостей:

Внедрение зависимостей позволяет писать слабосвязанный код, который легко отлаживать:

Например:

Когда ваша служба разделена на версию для разработки и онлайн-версию, вам могут понадобиться две разные службы devDataSevice и proDataSevice, Если вы не используете внедрение зависимостей, вам нужно заново внедрить эти два объекта в несколько компонентов, чтобы использовать эти две службы. При переключении между онлайн-средой и тестовой средой вам необходимо изменить код в нескольких компонентах. В форме внедрения зависимостей вам нужно только изменить код в провайдере, чтобы изменить службы во всех компонентах, что значительно снижает степень связанности кода и повышает удобство сопровождения.

Сначала создайте службу

import { Injectable } from '@angular/core';

@Injectable({
  providedIn: 'root',
})
export class HeroService {
  constructor() { }
}

Поставщик услуг (инжектор)

Где написать поставщика услуг:

  1. Параметры метаданных для createdIn в декораторе @Injectable() на самой службе

    Значением createdIn может быть «root» или конкретный NgModule.

  2. параметр метаданных провайдеров в декораторе NgModule @NgModule()

  3. Параметры метаданных провайдеров в декораторе компонента @Component()

  4. Опция метаданных провайдеров в декораторе директивы @Directive() (инжектор на уровне элемента)

Как писать в провайдерах:

provider:[ProductService]
provider:[{provide:ProductService,useClass:ProductService}]
provider:[{provide:ProductService,useClass:AnotherProductService}]
provider:[{provide:ProductService,useFactory:(参数A)=>{return ob},deps:[参数A]}]
provider:[{provide:"IS_DEV_ENV",useValue:{isDev:true}}]

Инжектор пузырится

  1. Angular попытается найти собственный инжектор компонента.
  2. Если инжектор компонента не находит соответствующего провайдера, он ищет инжектор своего родителя, пока Angular не найдет допустимый инжектор или не выйдет за пределы позиции предка в дереве компонентов.
  3. Angular выдает ошибку, если предок за пределами дерева компонентов не найден.

Внедрить сервис:

Вставить в конструктор:

construct(private productService:ProductService){...};
  1. @Optional() — декоратор для productService.Если провайдер сервиса не найден, значение параметра устанавливается равным нулю.
  2. Декоратор @Host() отключает поиск компонентов хоста. Хост-компонент обычно тот, который запрашивает зависимость. Однако, когда компонент проецируется в родительский компонент, этот родительский компонент становится хостом.
  3. Пользовательский поставщик @Inject()
  4. @Self() и @SkipSelf() для изменения способа поиска поставщиков.

@угловая/роутерная маршрутизация

  1. Установите базовый тег, чтобы сообщить маршруту, как синтезировать навигацию.
<!--index.html中的head标签中加入<base href="/">来告诉路由该如何合成导航用的 URL-->
<base href="/">
  1. Импорт конфигурации маршрутизации
//app.module.ts
//导入路由核心模块
import { Routes, RouterModule } from '@angular/router';

const routes: Routes = [
  {path:'**',component:AComponent}
];

@NgModule({
  ...
  imports: [RouterModule.forRoot(routes)]
  ...
})
export class AppModule { }

Введение в настройку маршрутизации маршрутов

  1. путь "**" означает соответствие всем

  2. redirectTo "представляет путь для перенаправления"

  3. pathMatch "полный" указывает степень соответствия

  4. компонент представляет компонент для отображения

  5. передача данных

  6. дети:[] дочерний маршрут

  7. canActivate:[PermissionGuard]

  8. canDeactivate:[FocusGuard]

  9. resolve:{Stock:StockResolve}

  10. выходная вспомогательная разводка

  11. Установите местоположение вывода навигации

<router-outlet></router-outlet>
<!-- Routed components go here -->

прыжок по маршруту

  1. Декларативный прыжок
<a [routerLink]="['/path']" routerLinkActive="active">routelink</a>
<a [routerLink]="['./path']">routelink</a>
<a [routerLink]="['{outlets:{aux:'aaa'}}']">routelink</a> 辅助路由 
http://localhost:4200/a(aux:aaa)
  1. императивный прыжок

Маршрутизатор может вызывать функцию навигации и навигацииByUrl().

Маршрутизация доставки данных:

//1.
[routerLink] = "['/path',1]"
//http://localhost:4200/path/1
// this.routeInfo.snapshot.queryParams
//2.
[routerLink]="['/b',1]" [queryParams]="{id:3}"
// http://localhost:4200/b/1?id=3
// this.routeInfo.snapshot.params
// 3.
{path:'a',component:AComponent,data:{id:666}} 
//this.routeInfo.snapshot.queryParams
//this.routeInfo.snapshot.data

ActivatedRoute Обычно используется: this.routeInfo см. выше

охранная маршрутизация

1.canActivate

export class PermissionGuard implements CanActivate{
  canActivate(){
    let hasPemission:boolean = Math.random() < 0.5;
    return hasPemission;
  }
}

2.canDeactivate

export class FocusGuard implements CanDeactivate<CComponent>{
  canDeactivate(component:CComponent){
    if(component.isFoucs){
      return true;
    }else {
      return confirm('不关注一下嘛?');
    }
  }
}

3.разрешить перед чтением данных

@Injectable()
export class StockResolve implements Resolve<Stock>{
  constructor(
    private route:Router
  ){}
  resolve(route:ActivatedRouteSnapshot,state:RouterStateSnapshot){
      return new Stock(1,'name');
  }
}

крючки жизненного цикла

Функции-ловушки запускаются при создании, обновлении и уничтожении компонентов или директив Angular.

Порядок выполнения хуков

  1. конструктор Это не хук жизненного цикла, но он должен быть выполнен первым
  2. ngOnChanges вызывается, когда входному свойству присваивается значение (неизменяемые изменения объекта)
  3. ngOnInit в первый раз после привязки данных и установки входного свойства директивы/компонента
  4. ngDoCheck вызывается сразу после ngOnChanges() и ngOnInit() в каждом цикле обнаружения изменений.
  5. ngAfterContentInit вызывается после того, как внешний контент проецируется в представление компонента/директивы
  6. ngAfterContentChecked Вызывается после обнаружения изменений содержимого проецируемого компонента.
  7. ngAfterViewInit вызывается после инициализации представления компонента и его подвидов.
  8. ngAfterViewChecked Вызывается после обнаружения изменения представления компонента и подпредставления
  9. ngOnDestroy вызывается перед директивой/компонентом уничтожения

фаза инициализации

//1.constructor 
//2.ngOnChanges
//3.ngOnInit
//4.ngDoCheck
//5.ngAfterContentInit
//6.ngAfterContentChecked
//7.ngAfterViewInit
//8.ngAfterViewChecked

стадия изменения

//1.ngOnChanges
//2.ngDoCheck
//3.ngAfterContentChecked
//4.ngAfterViewChecked

Фаза разрушения компонента

//1.ngOnDestroy
// 在路由变更时改变

ngAfterViewInit,ngAfterViewChecked

  1. Дочерний компонент будет собран только тогда, когда будет собран родительский компонент.
  2. Компонент вызывается после попытки сборки
  3. Данные просмотра не могут быть изменены в этом методе

ngaftercontentinit, ngaftercontentceckect, проекция

1.子组件
<div>
  <ng-content></ng-content>
</div>
2.父组件
<SComponent>
    <!--在此写入的东西会投影到子组件-->
</SComponent>

форма

  1. ReactiveFormsModuleReactive Forms
  2. Шаблоны форм FormsModule

шаблонная форма

  1. В angular автоматически добавляется ngForm для обработки формы, если angular не используется для обработки формы, добавляется ngNoForm.
  2. Добавьте #myForm="ngForm" в форму, вы можете использовать {{myForm.value | json}} на странице, чтобы определить, что объект значения ngModule в форме является значением имени

NgForm соответствует FormGroup

Ngmodel соответствует FormControl

ngModelGroup соответствует FormArray

<form #myForm="ngForm" action="/regist" (ngSubmit)="createUser(myForm.value)" method="post">
  <div>
    <input ngModel name="a" type="text" required pattern="[a-zA-Z0-9]+">
  </div>
  <div>
    second:<input ngModel #second="ngModel" name="a" type="text" required pattern="[a-zA-Z0-9]+">
  </div>
  <div>
    <input ngModel name="b" type="text" required pattern="[a-zA-Z0-9]+">
  </div>
  <div ngModelGroup="tow">
    <input ngModel name="a" type="text">
    <input ngModel name="b" type="text">
  </div>
  <button type="submit">提交</button>
</form>
<div>
  {{myForm.value | json}}
  <br>
  second值是:{{second.value}}
</div>

адаптивная форма

private nickName = new FormControl('tom');
private passwordInfo = new  FormGroup({
  password: new FormControl(),
  passwordConfirm:new  FormControl()
});
private email = new FormArray([
    new FormControl('a@a.com'),
    new FormControl('b@b.com')
]);

FormControl

Управление значением и состоянием достоверности одного элемента управления формы

FormGroup

Управление значением и состоянием достоверности набора экземпляров AbstractControl

FormArray

Управление значением и состоянием достоверности набора экземпляров AbstractControl

<form [formGroup]="formModel" action="/regist" (Submit)="createUser()" method="post">
   <input  formControlName="nikname">
   <ul formArrayName="emails">
      <li *ngFor="let email of formModel.get('emails').controls;let i = index;">
        <input [formControlName]="i">
      </li>
    </ul>
    <button >增加email.....</button>
   <input  formControlName="emails">
   <div formGroupName="passwordInfo">
      <input formControlName="password">
      <input formControlName="passwordConfirm">
    </div>
</form>

Синтаксис ярлыка FormBuilder

private formModel:FormGroup;
private fb:FormBuilder = new FormBuilder();
/*this.formModel = new FormGroup({
  nikname:new FormControl(),
  emails:new FormArray([
      new FormControl()
  ]),
  mobile:new FormControl(),
  passwordInfo:new FormGroup({
    password:new FormControl(),
    passwordConfirm:new FormControl()
  })
});*/
this.formModel = this.fb.group({
  nikname:[''],
  emails:this.fb.array([
      ['']
  ]),
  mobile:[''],
  passwordInfo:this.fb.group({
    password:[''],
    passwordConfirm:['']
  })
});

валидатор угловой формы

  //自定义校验器
  xxx(param:AbstractControl):{[key:string]:any}{
    return null;
  }
  // eg:
  moblieValid(moblie:FormControl):any{
    ..........
    // return null;表示成功
    // return {...};不成功
  }
  
  
  //预定义校验器
  Validators.required ......
  nikname:["xxxx",[Validators.required,.....]]
  .....................
  let niknameValid;boolean = this.formModel.get('nikname').valid;
  passwordInfo:this.fb.group({
      password:[''],
      passwordConfirm:['']
    },{validator:this.passwordValidator}) //一次校验多个字段
    

показать сообщение об ошибке

<div [hidden]="!formModel.hasError('required','nickname')"></div>

Поскольку статья слишком длинная, я снова открою статью о формах, httpclient и т. д., спасибо за вашу поддержку.