Angular4学习笔记

1.1angular模块

每个Angular应用至少有一个根模块,一般命名为app.module,跟模块用于声明和引入一些模块,如果不声明,就会报错。
模块的基本语法如下:

import { NgModule }      from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
@NgModule({
  imports:      [ BrowserModule ],    //这里一般导入angular的内部模块  BrowserModule注册了一些关键的应用服务提供商。 它还包括了一些通用的指令,例如NgIf和NgFor,所以这些指令在该模块的任何组件模板中都是可用的。
  providers:    [ Logger ],           //提供服务
  declarations: [ AppComponent ],     //声明应用程序创建的模块
  exports:      [ AppComponent ],     //导出模块。一般在根模块中不用 可用于其它模块的组件模板。
  bootstrap:    [ AppComponent ]      //主视图,就是决定根目录显示什么内容 只有根模块才能设置bootstrap属性。
})
export class AppModule { }

通常在main.ts文件中引导根模块,如下

import { enableProdMode } from '@angular/core';
import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';

import { AppModule } from './app/app.module';
import { environment } from './environments/environment';

if (environment.production) {
  enableProdMode();
}

platformBrowserDynamic().bootstrapModule(AppModule);

1.2angular模块库

下面是一些常用到的模块库(持续更新中……),导入语法:import { Component } from ‘@angular/core’;

  • import { Component } from ‘@angular/core’; 用于声明模块的类
  • import { BrowserModule } from ‘@angular/platform-browser’; BrowserModule注册了一些关键的应用服务提供商。 它还包括了一些通用的指令,例如NgIf和NgFor,所以这些指令在该模块的任何组件模板中都是可用的。
  • import { Input} from ‘@angular/core’; 用于模块间参数传递 eg:@Input() hero: Hero;
  • import { NgModule } from ‘@angular/core’; 用于视图数据绑定
  • import { OnInit} from ‘@angular/core’; 用于初始化事件调用export class LoginComponent implements OnInit {}
  • import { ViewChild,ElementRef} from ‘@angular/core’; 用于获取html元素,定义:@ViewChild('chart') private chartContainer: ElementRef; 使用:let element = this.chartContainer.nativeElement;
  • import { RouterModule, Routes } from ‘@angular/router’; 用于路由
  • import { Route } from ‘@angular/router’; 用于路由跳转this.router.navigate([‘/url’,传参数]);
  • import { ActivatedRoute, ParamMap } from ‘@angular/router’; 和上面搭配。用于获取传递的参数。eg:
this.route.paramMap
            .switchMap((params : ParamMap) => this.heroService.getHero(+params.get('id')))
            .subscribe(hero => this.hero = hero)
  • import { Location } from ‘@angular/common’; 用于浏览器跳转 eg:this.location.back();
  • import {FormsModule} from ‘@angular/forms’;
  • import {HttpClientModule} from ‘@angular/common/http’; 用于和后端浏览器通讯
@Component(...)
export class MyComponent implements OnInit {

  results: string[];

  // Inject HttpClient into your component or service.
  constructor(private http: HttpClient) {}

  ngOnInit(): void {
    // Make the HTTP request:
    this.http.get('/api/items').subscribe(data => {
      // Read the result field from the JSON response.
      this.results = data['results'];
    });
  }
}

1.3模块的定义

(1)模块定义
模块定义基本语法如下:

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

@Component({
  selector: 'app-root',                //选择器
  template:'<h1></h1>',               //可以直接写语句也可以如下应用模板
  templateUrl: './app.component.html',   //模板html的地址
  styleUrls: ['./app.component.css']     //css的地址
  providers:  [ HeroService ]  //注入的类
})

export class AppComponent implements OnInit {
  constructor() {
  }

  ngOnInit() {
  }
}

<app-root></app-root>  //使用

(2)生命周期

  • ngOnChanges() 当被绑定的输入属性的值发生变化时调用,首次调用一定会发生在ngOnInit()之前
  • ngOnInit() 在Angular第一次显示数据绑定和设置指令/组件的输入属性之后,初始化指令/组件。在第一轮ngOnChanges()完成之后调用,只调用一次。用途:在构造函数之后马上执行复杂的初始化逻辑。
  • ngDoCheck() 检测,并在发生Angular无法或不愿意自己检测的变化时作出反应。
  • ngAfterContentInit() 当把内容投影进组件之后调用 只调用一次。只适用于组件。
  • ngAfterContentChecked() 每次完成被投影组件内容的变更检测之后调用。只适合组件。
  • ngAfterViewInit() 初始化完组件视图及其子视图之后调用。只调用一次。只适合组件。
  • ngAfterViewChecked() 每次做完组件视图和子视图的变更检测之后调用。只适合组件。
  • ngOnDestroy 销毁指令/组件之前调用并清扫 。进行反订阅可观察对象和分离事件处理器。

1.4模板

用angular模板语法写的html代码,一般和component结合,链接地址放置在templateUrl
一些常用的模板语法(更新中……)

  • {{….}} 插入值(表达式)
<p>My current hero is {{currentHero.name}}</p>
<img src="{{heroImageUrl}}" style="height:30px">
<p>The sum of 1 + 1 is not {{1 + 1 + getVal()}}</p>
  • 属性绑定 [属性名] :方括号告诉 Angular 要计算模板表达式。 如果忘了加方括号,Angular 会把这个表达式当做字符串常量看待,并用该字符串来初始化目标属性。
<img [src]="heroImageUrl">   //元素  等同于<img src="{{heroImageUrl}}" >
<button [disabled]="isUnchanged">Cancel is disabled</button> //组件
<app-hero-detail [hero]="currentHero"></app-hero-detail> //组件
<div [ngClass]="{'special': isSpecial}"></div>  //指令
  • 事件绑定
<button (click)="onSave()">Save</button>
<div (myClick)="clickMessage=$event" clickable>click with myClick</div> //指令
<input [value]="currentHero.name"
       (input)="currentHero.name=$event.target.value" >

//在处理父指令到子指令传递event事件时:
   //子指令
<button (click)="delete()">Delete</button>   //html中

 @Output() deleteRequest = new EventEmitter<Hero>();     //ts中
delete() {  
  this.deleteRequest.emit(this.hero);
}

//父指令
<app-hero-detail (deleteRequest)="deleteHero($event)" [hero]="currentHero"></app-hero-detail>
  • 双向数据绑定 [(…)] ngModule
<input [(ngModel)]="currentHero.name">
//在使用ngModel指令进行双向数据绑定之前,我们必须导入FormsModule并把它添加到Angular模块的imports列表中。
import { NgModule } from '@angular/core';
import { BrowserModule }  from '@angular/platform-browser';
import { FormsModule } from '@angular/forms'; // 
@NgModule({
  imports: [
    BrowserModule,
    FormsModule  // <--- import into the NgModule
  ],
  /* Other module metadata */
})
export class AppModule { }
  • NgClass 指令 添加或移除一组CSS类
<div [ngClass]="currentClasses">This div is initially saveable, unchanged, and special</div>
  • NgStyle 添加或移除一组CSS样式
<div [ngStyle]="currentStyles">
  This div is initially italic, normal weight, and extra large (24px).
</div>
  • *ngIf 类似js的if
<div *ngIf="currentHero">Hello, {{currentHero.name}}</div>
  • *ngSwitch 类似js的switch
<div [ngSwitch]="currentHero.emotion">
  <app-happy-hero    *ngSwitchCase="'happy'"    [hero]="currentHero"></app-happy-hero>
  <app-sad-hero      *ngSwitchCase="'sad'"      [hero]="currentHero"></app-sad-hero>
  <app-confused-hero *ngSwitchCase="'confused'" [hero]="currentHero"></app-confused-hero>
  <app-unknown-hero  *ngSwitchDefault           [hero]="currentHero"></app-unknown-hero>
</div>
  • *ngForOf 类似js的for of
<div *ngFor="let hero of heroes">{{hero.name}}</div>
<app-hero-detail *ngFor="let hero of heroes" [hero]="hero"></app-hero-detail>
<div *ngFor="let hero of heroes; let i=index">{{i + 1}} - {{hero.name}}</div>
  • 带trackBy的*ngFor
trackByHeroes(index: number, hero: Hero): number { return hero.id; }
<div *ngFor="let hero of heroes; trackBy: trackByHeroes">
  ({{hero.id}}) {{hero.name}}
</div>
  • <ng-template>是一个 Angular 元素,用来渲染HTML。
  • <ng-container>是一个分组元素,但它不会污染样式或元素布局,因为 Angular 压根不会把它放进 DOM 中
<p>
  I turned the corner
  <ng-container *ngIf="hero">
    and saw {{hero.name}}. I waved
  </ng-container>
  and continued on my way.
</p>
  • #var 引入变量 类似react的ref
<input ref-fax placeholder="fax number">
<button (click)="callFax(fax.value)">Fax</button>
  • @input @output :在子组件引入父组件的元素时,@Input往往是值,@Output是指事件
@Input()  hero: Hero;
@Output() deleteRequest = new EventEmitter<Hero>();
  • 管道指令
<div>Title through uppercase pipe: {{title | uppercase}}</div>   //大写
<div>
  Title through a pipe chain:
  {{title | uppercase | lowercase}}                           //小写,可串联
</div>
<div>Birthdate: {{currentHero?.birthdate | date:'longDate'}}</div>  //日期
<div>{{currentHero | json}}</div>                //转为json格式
  • 安全操作符 ?. !非空断言 :表示存在就执行后面的操作
The current hero's name is {{currentHero?.name}}
<div *ngIf="hero">
  The hero's name is {{hero!.name}}
</div>
  • ElementRef :可以封装不同平台下视图层中的 native 元素,在constructo注入,然后通过this.elementRef.nativeElement获取dom元素
constructor(private elementRef: ElementRef) {
 }
const rootMenu = this.elementRef.nativeElement.querySelectorAll('.ant-menu-submenu.ant-menu-submenu-horizontal');

1.5服务

服务一般是封装了一堆方法的类
一般在根组件中注册 providers: [DataTableService]
然后在使用的组件的constuctor中注入

 constructor(private store: Store<State>,
              private dataTable: DataTableService,
              private dataTask: DataTaskService,
              private _message: NzMessageService) {}
 //使用时 this.store.select()

(1)依赖注入: 就是在 class的构造函数中注入外部类,而不必亲自创建它。
(2)为什么要用 @Injectable()?
@Injectable() 标识一个类可以被注入器实例化。 通常,在试图实例化没有被标识为@Injectable()的类时,注入器会报错。

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

import { HEROES }     from './mock-heroes';
import { Logger }     from '../logger.service';

@Injectable()
export class HeroService {

  constructor(private logger: Logger) {  }

  getHeroes() {
    this.logger.log('Getting heroes ...');
    return HEROES;
  }
}

(3)

1.6交互

1.@input 和 @output 绑定把数据从父组件传到子组件
(1)父组件

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

import { HEROES } from './hero';

@Component({
  selector: 'app-hero-parent',
  template: `
    <h2>{{master}} controls {{heroes.length}} heroes</h2>
    <app-hero-child *ngFor="let hero of heroes"
      [hero]="hero"
      [master]="master">
    </app-hero-child>
  `
})
export class HeroParentComponent {
  heroes = HEROES;
  master = 'Master';
}

(2)子组件

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

import { Hero } from './hero';

@Component({
  selector: 'app-hero-child',
  template: `
    <h3>{{hero.name}} says:</h3>
    <p>I, {{hero.name}}, am at your service, {{masterName}}.</p>
  `
})
export class HeroChildComponent {
  //直接不处理
  @Input() hero: Hero;
  @Input('master') masterName: string;   //区别名  不采用 

  //或者采用setter处理
   private _masterName = '';
  @Input()
  set masterName(masterName: string) {
    this._masterName = (masterName&& masterName.trim()) || '<no name set>';
  }
  get masterName(): string { return this._masterName; }
}

2.ngOnChanges

ngOnChanges(changes: {[propKey: string]: SimpleChange}) {
    let log: string[] = [];
    for (let propName in changes) {
      let changedProp = changes[propName];       
      let to = JSON.stringify(changedProp.currentValue);  //当前值 
      if (changedProp.isFirstChange()) {
        log.push(`Initial value of ${propName} set to ${to}`);  //propName 改变的变量名
      } else {
        let from = JSON.stringify(changedProp.previousValue);  //以前的值
        log.push(`${propName} changed from ${from} to ${to}`);
      }
    }
    this.changeLog.push(log.join(', '));
  }

3.父组件监听子组件的事件(见上面的1.4的事件绑定)
(1)父组件 : 父组件绑定到这个事件属性,并在事件发生时作出回应。
(2)子组件 :子组件暴露一个EventEmitter属性,当事件发生时,子组件利用该属性emits(向上弹射)事件。
4.父组件调用子组件的方法 变量 : 通过父组件定义一个变量#var来代表子组件,父组件-子组件的连接必须全部在父组件的模板中进行,例如:

import { Component }                from '@angular/core';
import { CountdownTimerComponent }  from './countdown-timer.component';

@Component({
  selector: 'app-countdown-parent-lv',
  template: `
  <h3>Countdown to Liftoff (via local variable)</h3>
  <button (click)="timer.start()">Start</button>
  <button (click)="timer.stop()">Stop</button>
  <div class="seconds">{{timer.seconds}}</div>
  <app-countdown-timer #timer></app-countdown-timer>
  `,
  styleUrls: ['../assets/demo.css']
})
export class CountdownLocalVarParentComponent { }

//这里的#timer代表子组件,然后父组件可以调用子组件的start() stop()方法了

5.父组件的类需要读取子组件的属性值或调用子组件的方法:子组件作为ViewChild,注入到父组件里面

import { AfterViewInit, ViewChild } from '@angular/core';
import { Component }                from '@angular/core';
import { CountdownTimerComponent }  from './countdown-timer.component';

@Component({
  selector: 'app-countdown-parent-vc',
  template: `
  <h3>Countdown to Liftoff (via ViewChild)</h3>
  <button (click)="start()">Start</button>
  <button (click)="stop()">Stop</button>
  <div class="seconds">{{ seconds() }}</div>
  <app-countdown-timer></app-countdown-timer>
  `,
  styleUrls: ['../assets/demo.css']
})
export class CountdownViewChildParentComponent implements AfterViewInit {

  @ViewChild(CountdownTimerComponent)
  private timerComponent: CountdownTimerComponent;

  seconds() { return 0; }  //被注入的计时器组件只有在Angular显示了父组件视图之后才能访问,所以我们先把秒数显示为0.

  ngAfterViewInit() {
    setTimeout(() => this.seconds = () => this.timerComponent.seconds, 0);
  }
//然后Angular会调用ngAfterViewInit生命周期钩子,但这时候再更新父组件视图的倒计时就已经太晚了。Angular的单向数据流规则会阻止在同一个周期内更新父组件视图。我们在显示秒数之前会被迫再等一轮。使用setTimeout()来等下一轮,然后改写seconds()方法,这样它接下来就会从注入的这个计时器组件里获取秒数的值。

  start() { this.timerComponent.start(); }
  stop() { this.timerComponent.stop(); }
}

6.父组件和子组件通过服务通信
例如rxjs在服务中创建observable 在子组件和父组件中订阅它

1.7样式

1.:host 获取宿主元素

:host(.active) {
  border-width: 3px;
}

2.:host-context 它在当前组件宿主元素的祖先节点中查找 CSS 类, 直到文档的根节点为止。在与其它选择器组合使用时,它非常有用。

:host-context(.theme-light) h2 {
  background-color: #eef;
}

3.::ng-deep 它不但作用于组件的子视图,也会作用于组件的内容。

1.8自定义属性指令

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

@Directive({
  selector: '[appHighlight]'
})
export class HighlightDirective {

  constructor(private el: ElementRef) { }

  @Input('appHighlight') highlightColor: string;  //判断值

  @HostListener('mouseenter') onMouseEnter() {       //事件
    this.highlight(this.highlightColor || 'red');
  }

  @HostListener('mouseleave') onMouseLeave() {
    this.highlight(null);
  }

  private highlight(color: string) {
    this.el.nativeElement.style.backgroundColor = color;  
  }
}

使用: <p [appHighlight]="color">Highlight me!</p>

1.9自定义管道

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

//使用 <p>Super power boost: {{2 | exponentialStrength: 10}}</p>

2.0非纯管道

AsyncPipe接受一个Promise或Observable作为输入,并且自动订阅这个输入,最终返回它们给出的值。使用方式时加上async

<p>Message: {{ message$ | async }}</p>

2.1动画

<li *ngFor="let hero of heroes"
    [@heroState]="hero.state"
    (click)="hero.toggleState()">
  {{hero.name}}
</li>

//active转变
animations: [
    trigger('heroState', [
      state('inactive', style({
        backgroundColor: '#eee',
        transform: 'scale(1)'
      })),
      state('active',   style({
        backgroundColor: '#cfd8dc',
        transform: 'scale(1.1)'
      })),
      transition('inactive => active', animate('100ms ease-in')),
      transition('active => inactive', animate('100ms ease-out'))
      //可以写成 transition('inactive => active, active => inactive',
 animate('100ms ease-out'))
     //或者 transition('inactive <=> active', animate('100ms ease-out'))
    ])
  ]

//进场 离场
animations: [
  trigger('flyInOut', [
    state('in', style({transform: 'translateX(0)'})),
    transition('void => *', [
      style({transform: 'translateX(-100%)'}),
      animate(100)
    ]),
    transition('* => void', [
      animate(100, style({transform: 'translateX(100%)'}))
    ])
  ])
]

//自动计算高度 *
animations: [
  trigger('shrinkOut', [
    state('in', style({height: '*'})),
    transition('* => void', [
      style({height: '*'}),
      animate(250, style({height: 0}))
    ])
  ])
]

//并行动画
animations: [
  trigger('flyInOut', [
    state('in', style({width: 120, transform: 'translateX(0)', opacity: 1})),
    transition('void => *', [
      style({width: 10, transform: 'translateX(50px)', opacity: 0}),
      group([
        animate('0.3s 0.1s ease', style({
          transform: 'translateX(0)',
          width: 120
        })),
        animate('0.3s ease', style({
          opacity: 1
        }))
      ])
    ]),
    transition('* => void', [
      group([
        animate('0.3s ease', style({
          transform: 'translateX(50px)',
          width: 10
        })),
        animate('0.3s 0.2s ease', style({
          opacity: 0
        }))
      ])
    ])
  ])
]

2.1路由

//appRoutes 加入AppModule的imports数组中
const appRoutes: Routes = [
  { path: 'crisis-center', component: CrisisListComponent }, //路由不能以“/”开头

  { path: 'hero/:id',      component: HeroDetailComponent }, 
  //路由中的:id是一个路由参数的令牌(Token)。比如/hero/42这个URL中,“42”就是id参数的值。
  {
    path: 'heroes',
    component: HeroListComponent,
    data: { title: 'Heroes List' }
  },
  { path: '',
    redirectTo: '/heroes',
    pathMatch: 'full'
  },
  //空路径('')表示应用的默认路径。

  { path: '**', component: PageNotFoundComponent }
  //路由中的**路径是一个通配符。当所请求的URL不匹配前面定义的路由表中的任何路径时,路由器就会选择此路由。 这个特性可用于显示“404 - Not Found”页,或自动重定向到其它路由。
];

或者和<router-outlet></router-outlet>配合嵌套子页面

import { AuthGuard }                from '../auth-guard.service';

const adminRoutes: Routes = [
  {
    path: 'admin',
    component: AdminComponent,  //父页面
    canActivate: [AuthGuard],   //这个做权限管理,没有登陆就返回登陆页面
    children: [
      {
        path: '',
        children: [
          { path: 'crises', component: ManageCrisesComponent },  //子页面
          { path: 'heroes', component: ManageHeroesComponent },
          { path: '', component: AdminDashboardComponent }
        ],
      }
    ]
  }
];

@NgModule({
  imports: [
    RouterModule.forChild(adminRoutes)
  ],
  exports: [
    RouterModule
  ]
})
export class AdminRoutingModule {}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值