Цель этой статьи — быстро начать разработку под углом или быстро понять статьи, посвященные разработке под углом.
Строительство окружающей среды
- Установка строительных лесов: npm i -g @angular/cli
- Новый проект: ng new my-app
Если установочные леса сообщают об ошибке, принудительно очистите кеш npm и переустановите его.
Компоненты и шаблоны
После того, как вы скачаете официальный список программ, вы можете быть не знакомы с директорией, поэтому пока не зацикливайтесь на ней, статья посвящена тому, как быстро начать работу с angular проектом.
Понимание контекста выражения шаблона
Переменные контекста в выражениях состоят из следующих трех типов:
- Переменные шаблона (объект $event шаблона, входные переменные шаблона (let hero) и ссылочные переменные шаблона (#heroForm))
- Контекстные переменные для директив (атрибуты в директивах)
- Переменные-члены компонентов (столбцы экземпляра компонента)
При наличии одного и того же порядка приоритета переменных выражения: переменная шаблона >> переменная контекста директивы >> переменная-член компонента
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 между несколькими атрибутами и свойствами HTML, такими как id.
- Некоторые атрибуты HTML не имеют соответствующих свойств, например colspan.
- Некоторые свойства DOM не имеют соответствующих атрибутов, например textContent.
Привязка шаблона Angular работает через свойства и события, а не атрибуты
привязка специального атрибута
[attr.aria-label]="actionName"
<td [attr.colspan]="1 + 1">
инструкция
Существует три типа команд:
- Компоненты — директивы с шаблонами
- Структурные директивы — директивы, которые изменяют макет DOM, добавляя и удаляя элементы DOM.
- Атрибутные директивы — директивы, которые изменяют внешний вид и поведение элементов, компонентов или других директив.
директива атрибута
- ngClass
- ngStyle
- ngModel
Структурные директивы
- ngIf
- ngFor
- 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() вставляет дочерний компонент (используется в классе компонентов)
- Доступ к внедренным дочерним компонентам возможен только после того, как Angular покажет представление родительского компонента (доступ во время жизненного цикла ngAfterViewInit)
- Правило одностороннего потока данных Angular предотвращает обновление представлений родительских компонентов в одном и том же цикле. Приложение вынуждено ждать еще один раунд, прежде чем отображать секунды.
- Обходной путь: используйте setTimeout() для изменения данных
@ViewChild(ChildComponent)
private childComponent: ChildComponent;
ngAfterViewInit() {
setTimeout(() => this.seconds = () => this.childComponent.changeData, 0);
}
6. Изменение данных через сервисы (используется в любой компонентной структуре)
пользовательская директива
ng g d myDirective/demo
- директива атрибута
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>
- Структурные директивы
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);
}
}
Чистые и нечистые трубы
-
Angular выполнит чистый канал только в том случае, если обнаружит чистое изменение входного значения. Чистые изменения — это изменения значений примитивного типа (String, Number, Boolean, Symbol) или изменения ссылок на объекты (Date, Array, Function, Object).
-
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() { }
}
Поставщик услуг (инжектор)
Где написать поставщика услуг:
-
Параметры метаданных для createdIn в декораторе @Injectable() на самой службе
Значением createdIn может быть «root» или конкретный NgModule.
-
параметр метаданных провайдеров в декораторе NgModule @NgModule()
-
Параметры метаданных провайдеров в декораторе компонента @Component()
-
Опция метаданных провайдеров в декораторе директивы @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}}]
Инжектор пузырится
- Angular попытается найти собственный инжектор компонента.
- Если инжектор компонента не находит соответствующего провайдера, он ищет инжектор своего родителя, пока Angular не найдет допустимый инжектор или не выйдет за пределы позиции предка в дереве компонентов.
- Angular выдает ошибку, если предок за пределами дерева компонентов не найден.
Внедрить сервис:
Вставить в конструктор:
construct(private productService:ProductService){...};
- @Optional() — декоратор для productService.Если провайдер сервиса не найден, значение параметра устанавливается равным нулю.
- Декоратор @Host() отключает поиск компонентов хоста. Хост-компонент обычно тот, который запрашивает зависимость. Однако, когда компонент проецируется в родительский компонент, этот родительский компонент становится хостом.
- Пользовательский поставщик @Inject()
- @Self() и @SkipSelf() для изменения способа поиска поставщиков.
@угловая/роутерная маршрутизация
- Установите базовый тег, чтобы сообщить маршруту, как синтезировать навигацию.
<!--index.html中的head标签中加入<base href="/">来告诉路由该如何合成导航用的 URL-->
<base href="/">
- Импорт конфигурации маршрутизации
//app.module.ts
//导入路由核心模块
import { Routes, RouterModule } from '@angular/router';
const routes: Routes = [
{path:'**',component:AComponent}
];
@NgModule({
...
imports: [RouterModule.forRoot(routes)]
...
})
export class AppModule { }
Введение в настройку маршрутизации маршрутов
-
путь "**" означает соответствие всем
-
redirectTo "представляет путь для перенаправления"
-
pathMatch "полный" указывает степень соответствия
-
компонент представляет компонент для отображения
-
передача данных
-
дети:[] дочерний маршрут
-
canActivate:[PermissionGuard]
-
canDeactivate:[FocusGuard]
-
resolve:{Stock:StockResolve}
-
выходная вспомогательная разводка
-
Установите местоположение вывода навигации
<router-outlet></router-outlet>
<!-- Routed components go here -->
прыжок по маршруту
- Декларативный прыжок
<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)
- императивный прыжок
Маршрутизатор может вызывать функцию навигации и навигации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.
Порядок выполнения хуков
- конструктор Это не хук жизненного цикла, но он должен быть выполнен первым
- ngOnChanges вызывается, когда входному свойству присваивается значение (неизменяемые изменения объекта)
- ngOnInit в первый раз после привязки данных и установки входного свойства директивы/компонента
- ngDoCheck вызывается сразу после ngOnChanges() и ngOnInit() в каждом цикле обнаружения изменений.
- ngAfterContentInit вызывается после того, как внешний контент проецируется в представление компонента/директивы
- ngAfterContentChecked Вызывается после обнаружения изменений содержимого проецируемого компонента.
- ngAfterViewInit вызывается после инициализации представления компонента и его подвидов.
- ngAfterViewChecked Вызывается после обнаружения изменения представления компонента и подпредставления
- 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
- Дочерний компонент будет собран только тогда, когда будет собран родительский компонент.
- Компонент вызывается после попытки сборки
- Данные просмотра не могут быть изменены в этом методе
ngaftercontentinit, ngaftercontentceckect, проекция
1.子组件
<div>
<ng-content></ng-content>
</div>
2.父组件
<SComponent>
<!--在此写入的东西会投影到子组件-->
</SComponent>
форма
- ReactiveFormsModuleReactive Forms
- Шаблоны форм FormsModule
шаблонная форма
- В angular автоматически добавляется ngForm для обработки формы, если angular не используется для обработки формы, добавляется ngNoForm.
- Добавьте #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>