Angular2——小结

入坑

前端开发者估计跟我的心思是一样的,刚对AngularJS写出了点头绪,懂了点皮毛,转眼升级版Angular4.x就出现了,心中是各种礼貌的问候的。。。

表情包1

默默擦眼泪。。。我们来看下要从哪几个方面入手。以下目录~

  • 路由
  • 指令
  • 组件
  • 模块
  • 服务

Angular抛弃了原本的 ng-controller指令、复杂的$scope,保留了路由嵌套、依赖注入机制。还有一些指令的写法,例如ng-click 改成(click) 、ng-repeat改成 *ngFor等等,后续指令篇会详细提出。Angular的最大改造是用Typescript为默认开发语言,组件化的思维。

入坑前需要了解一下Angular-Cli工具。在项目初始化的时候,可以开箱即用,搭配一系列完整的工具

npm install @angular/cli -g
ng new study-ng
cd study-ng
ng serve

打开package.json文件

    "@angular/animations": "^5.2.0",
    "@angular/common": "^5.2.0",
    "@angular/compiler": "^5.2.0",
    "@angular/core": "^5.2.0",
    "@angular/forms": "^5.2.0",
    "@angular/http": "^5.2.0",
    "@angular/platform-browser": "^5.2.0",
    "@angular/platform-browser-dynamic": "^5.2.0",
    "@angular/router": "^5.2.0",

  • @angular/common:
    • CommonModule:通用模块,包含内置指令ngIf,ngFor
  • @angular/core:包含多种常用的模块
    • NgModule(模块定义装饰器)
    • Component(组件定义装饰器)
    • Directive (指令定义装饰器)
    • ElemtRef (元素引用)
    • ViewChild (获取子元素)
    • Output Input EventEmitter Render 等等等。。。。
  • @angular/forms:
    • Validators:表单校验
  • @angular/http:
    • HttpModule:http请求模块
  • @angular/router:
    • RouterModule:路由模块

天啊噜!!太多了。~~ps:这些都是撸过代码后从头看理论概念的时候能理解透的。。。硬生生的啃文字,小火鸡我是受不了的。。。

表情包2

生命周期

组件周期钩子函数 说明
constructor(myService:MyService) 类的构造器会再其他生命周期函数前调用,在该方法中完成服务的依赖注入
ngOnChanges 当被绑定的输入属性的值发生变化时调用,首次调用一定会发生在 ngOnInit之前。(@input属性(输入属性)发生变化时,会调用。非此属性,不会调用。)
ngOnInit 只执行一次,dom操作可放在其中
ngDoCheck 更新检测机制,如果组件内发生异步事件,就会检查整个组件树
ngAfterContentInit 组件内容初始化之后调用
ngAfterContentChecked
ngAfterViewInit 组件视图初始化后调用
ngAfterViewChecked
ngOnDestroy 实例被销毁前调用,仅调用一次

进入正文啦 ~


image.png

一、路由篇

1、route设置三步走

(1)、手动添加路由文件

image

appRoutes的配置

import { Routes } from "@angular/router";
//引入组件等。。。。
import { ChildComponent } from'./home/child/child.component'

//定义并输出常量路由
export const appRoutes:Routes=[
  //地址栏输入 .../example,加载组件ExampleComponentComponent
  { path:'example',component:ExampleComponentComponent},
  { path:'home',
    component:HomeComponent,
    children:[{//子路由   .../home/home-child,加载ChildComponent组件
      path:'child',
      component:ChildComponent,
      //children:...
    }]
  },
  { path:'home/brother',component:BrotherComponent},//下图示例
  {
    //如果 地址栏没输入定义的路由就跳转到home路由界面
    path:'',
    redirectTo:'home',
    pathMatch:'full'
  }
]

子路由的区别

child组件是通过一级路由被载入到homeComponent的html模板的<router-outlet>下方

  <div routerLink="/example">栗子</div>

  <div routerLink="./brother">brother</div>

  <div routerLink="child">child的内容会展示在当页面  router-outlet  中</div>
  <!-- <div [routerLink]="['./child']">child的内容会展示在当页面---另一种写法</div> -->
  <router-outlet></router-outlet>

<router-outlet>路由占位符,可以理解为渲染路由组件的区域,一个组件只有一个无名的<router-outlet>可以有多个有名的<router-outlet>,例如:<router-outlet name=”a”><router-outlet name=”b”>

(2)、app.module.ts文件中引用

import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { RouterModule } from '@angular/router'
import { appRoutes } from './route.module'
import { AppComponent } from './app.component';

@NgModule({
  declarations: [
    AppComponent,
  ],
  imports: [
    //注入模块中,forChild只能用于子路由,forRoot只能用于根模块
    // forRoot有一个可选的配置参数,里面有四个选项
    // enableTracing :在console.log中打印出路由内部事件信息
    // useHash :把url改成hash风格 /#/
    // initialNavigation : 禁用初始导航,没用过。。
    // errorHandler :使用自定义的错误处理,来抛出报错信息;
    RouterModule.forRoot(appRoutes,{useHash: true}),   //添加 !!
    BrowserModule,
  ],
  providers: [],
  bootstrap: [AppComponent]
})
export class AppModule { }

(3)、在index.html中添加

<body>
  <app-root></app-root>
</body>

2、其他注意点

(1)、路由跳转中可加上参数

import { Component, OnInit } from '@angular/core';
import {  Router } from '@angular/router';

@Component({
 //忽略...
})
export class HomeComponent implements OnInit {

  constructor(
    public router:Router
  ) { }

  goTopage(page,queryParams){
    this.router.navigate([page],{ queryParams: queryParam })
  }
}

ps:可通过navigate()方法来实现页面跳转

(2)、forChild的使用

根模块中使用forRoot(),子模块中使用forChild()

import { NgModule } from '@angular/core';
import { Routes, RouterModule } from '@angular/router';
export const routes: Routes = [];

@NgModule({
  imports: [
    RouterModule.forChild(routes)
  ],
  // ...
})
export class ChildModule {  }

二、指令篇

  • 结构指令

1、 NgClass:接收一个对象,key为class名,value为值,表示是否用改样式

<p [ngClass]="{'fadeIn'}">example</p>
<p [ngClass]="{'fadeIn':!hidden}">example</p>

2、NgStyle:设置dom元素的css属性,可以动态的

<div [ngStyle]="{'color':'#999'}">写样式的东西咯</div>
<div [ngStyle]="{'color':gray?'#999':'#000'}">写样式的东西咯</div>

3、NgFor:创建dom元素,类似ng1中的ng-repeat

    const list = [ {name:'a'} ,{name:'b'}]
    const array = [1,2,3,4]
<ul>
    <li *ngFor="let item of list"></li>
</ul>
<ul>
    <li *ngFor="let item of array,let i = index">第个</li>
</ul>

4、NgIf:设置dom元素的展示或隐藏

<div *ngIf="show">要不要展示咧?<div>
  • 自定义属性指令

当内置指令还不能满足实际业务场景时,Angular中提供了自定义指令来满足特定的场景需求

举个栗子:给用自定义属性的内容加点特殊处理

1、第一步,创建一个directive文件

ng generate directive child-directive

此时app.module中已增加ChildDirectiveDirective指令

2、第二步,在模块中引入我们定义的指令

//...
@NgModule({
  imports: [ BrowserModule ],
  declarations: [
    AppComponent,
    ChildDirectiveDirective//!!申明我们定义的指令
  ],
  bootstrap: [ AppComponent ]
})
//...

3、第三步,撸出directive的逻辑

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

@Directive({//@Directive装饰器指定了一个选择器名称,用于指出与此指令相关联的属性的名字
  selector: 'color,[color]'
})
export class ChildDirectiveDirective {
  @Input('color')color : any;//@Input 为组件提供数据
  private elem;
  constructor(private renderer:Renderer2,elementRef:ElementRef) { 
    this.elem = elementRef//elementRef可直接获取到dom
  }
  ngOnInit(){
    this.renderer.setStyle(this.elem.nativeElement,'color',this.color)//让页面上该dom渲染该样式
  }
}

4、第四步,在html中引用该自定义属性

组件中添加该指令,可自定义展示的样式

<div [color]='"red"'>测试下咯</div>

三、组件

是时候祭出我的超简单基础组件第一套!!!switch组件的实现

look look 组件实现的部分

  • 1、 第一步,实现switch的样式

首先把switch轮子的样式写好


  • switch.component.html
    <span>
    <label class="iSwitch">
      <input type="checkbox" (click)="switch($event)" #switchInput >
      <i></i>
    </label> 
    </span>
    
    

具体css样式怎么撸的我就不贴了,自行撸!下面主要讲组件的实现

  • 2、 第二步,实现switch轮子的逻辑
  • switch.component.ts
import { Component, OnInit, Output, EventEmitter, Input, ViewChild,ElementRef,Renderer2 } from '@angular/core';

@Component({
    selector:'switch',//selector就是使用该组件时候的标签名字
    templateUrl:'./switch.component.html',
    styleUrls:['./switch.component.scss']
})

export class SwitchComponent implements OnInit {
  public open:boolean;
  @ViewChild('switchInput' , {read: ElementRef}) switchInput: ElementRef;
  //ElementRef 直接获取了轮子中<input>dom元素
  @Output() onchange: EventEmitter<any> = new EventEmitter<any>();
  //前面提到@input,可以从demo子组件中获取数据,@output则相当于方法的绑定,将onchange方法绑定到demo中,在父作用域中处理事件。output一般都是一个EventEmitter实例,通过emit()方法将父组件取到的值返回给demo子组件中
  constructor(private renderer: Renderer2 ,) { }
  ngOnInit() {
  }
  switch(e){
    this.open = !this.open
    this.onchange.emit(this.switchInput.nativeElement.checked)//返回给子组件demo中
  }
}

  • 3、 第三步,使用轮子的方式

使用轮子的代码,使用的方法:

demo.component.html

<switch (onchange)="getSwitchVaule($event)"></switch>

demo.component.ts

 export class SwitchDemo { 
  public getSwitchVaule(v){
    //页面中的onchange方法是父组件提供的 
    console.log(‘结果:’,v) 
  }
}

暂停一下,来一些啰嗦!!

看到这是否还会一脸懵逼???我们来解读下实现的过程。

使用<switch>标签名,可以实例化一个switch组件。</p>

获取到父组件通过@Output提供的onchange方法,在这个方法中,<switch>父组件处理switch开关的值,处理后的值。通过emit()方法返还给demo组件中的 public getSwitchVaule(v)方法中

  • 4、第四步,给轮子增加点初始值

接着我们就会思考switch组件是否可以添加一些默认值,进入页面默认就是打开的状态。

也就是demo组件如何给父组件通信,告诉父组件我现在是打开的状态,这里可以借助添加属性的方法来实现

<switch (onchange)="getSwitchVaule($event)" [default]=true>

[defalut]是一个自定义的属性,并且传值true,可在父组件轮子中去获取demo的传值

//...
export class SwitchComponent implements OnInit {
  @Input('default') defaultData: any;//默认关闭状态
  constructor(...) { }
  ngOnInit(){
    this.initDefault();//设置一个获取初始默认值的函数
  }
  initDefault(){
    //this.defaultData 可获取到demo组件中传值过来的true
    if(this.defaultData){
      this.switchInput.nativeElement.checked = true;//设置页面switch的开关状态
      this.open = !this.open
    }
  }
} 
//...

  • 5、最后一点,自行思考!!!

现在switch组件已经可以支持点击打开或者关闭开关,并且可接收一个默认开关值。至于switch的禁用状态disabled也同理可实现,这个大家就自行思考啦~道理都是一样的啦 ~~~

四、模板

五、服务

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 217,406评论 6 503
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,732评论 3 393
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 163,711评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,380评论 1 293
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,432评论 6 392
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,301评论 1 301
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,145评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,008评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,443评论 1 314
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,649评论 3 334
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,795评论 1 347
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,501评论 5 345
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,119评论 3 328
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,731评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,865评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,899评论 2 370
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,724评论 2 354

推荐阅读更多精彩内容