入坑
前端开发者估计跟我的心思是一样的,刚对AngularJS写出了点头绪,懂了点皮毛,转眼升级版Angular4.x就出现了,心中是各种礼貌的问候的。。。
![](https://img.haomeiwen.com/i826433/3dc6bfd3dd273bc3.jpeg)
默默擦眼泪。。。我们来看下要从哪几个方面入手。以下目录~
- 路由
- 指令
- 组件
- 模块
- 服务
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:这些都是撸过代码后从头看理论概念的时候能理解透的。。。硬生生的啃文字,小火鸡我是受不了的。。。
![](https://img.haomeiwen.com/i826433/771fdd4cf6466b63.jpeg)
生命周期
组件周期钩子函数 | 说明 |
---|---|
constructor(myService:MyService) | 类的构造器会再其他生命周期函数前调用,在该方法中完成服务的依赖注入 |
ngOnChanges | 当被绑定的输入属性的值发生变化时调用,首次调用一定会发生在 ngOnInit之前。(@input属性(输入属性)发生变化时,会调用。非此属性,不会调用。) |
ngOnInit | 只执行一次,dom操作可放在其中 |
ngDoCheck | 更新检测机制,如果组件内发生异步事件,就会检查整个组件树 |
ngAfterContentInit | 组件内容初始化之后调用 |
ngAfterContentChecked | |
ngAfterViewInit | 组件视图初始化后调用 |
ngAfterViewChecked | |
ngOnDestroy | 实例被销毁前调用,仅调用一次 |
进入正文啦 ~
![](https://img.haomeiwen.com/i826433/41d50efff276de4d.png)
一、路由篇
1、route设置三步走
(1)、手动添加路由文件
![](https://img.haomeiwen.com/i826433/46726c435dbb4068.png)
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'
}
]
![](https://img.haomeiwen.com/i826433/1d4ba6219e770de8.jpg)
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轮子的样式写好
![](https://img.haomeiwen.com/i826433/80a4dfba2468b3db.png)
- 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也同理可实现,这个大家就自行思考啦~道理都是一样的啦 ~~~
网友评论