Angular

一、数据绑定的四种形式:

(1)插值    <p>{{title}}</p>html

(2)属性绑定     <img [src]="userUrl"/>es6

(3)事件绑定     <button (click)='onSave()'>点击</button>json

(4)双向绑定     <input [(ngModel)]='title'/>服务器

        在双向绑定中,数据属性值经过属性绑定从组件流到输入框,当修改输入框内容时经过事件绑定流回组件,把属性值设为最新值。网络

 

选择属性绑定仍是插值?app

  当渲染的数据类型是字符串时,倾向于可读性更好的插值;可是当数据类型不是字符串时,必须用属性绑定了。dom

属性绑定与attribute绑定的区别?curl

  用属性绑定来设置元素的属性老是好于用字符串设置attribute,可是当元素没有属性可绑时,就必须用attribute绑定。函数

       如:  colspan不是td的属性布局

<tr><td [attr.colspan]="1+1">One-Two</td></tr>

CSS类绑定

  • 全有或全无的替换型绑定

   <div class='bad curly special' [class]='isTrue'></div>

  • 绑定到特定类名    单个class的添加与移除

   <div [class.special]='isTrue'></div>

           同时添加或移除多个class

     <div [ngClass]="{'background':isBg,'fontColor':isFontColor}"></div>

样式绑定

  • 单个样式绑定   <button [style.color]="isSpecial?'red':'green'"></button>

二、指令

(1)结构型指令:经过添加、移除或替换DOM来修改布局。如 *ngIf、*ngFor

(2)属性型指令:会修改现有元素的外观或行为。 如 NgClass、NgStyle、NgModel

2.一、为何要给结构型指令加上“*”?

  星号是用来简化更复杂语法的“语法糖”,从内部实现来讲,Angular把*ngIf属性翻译成了一个<ng-template>元素,并用它来包裹宿主元素

   如<div *ngIf="hero">hero</div>  =======》

    <ng-template [ngIf]="hero">
      <div>hero</div>
    </ng-template>

2.二、*ngIf有else

<div *ngIf="display else noData"></div>
<ng-template #noData></ng-template>

在Angular中一个标签上不能同时使用两个指令,能够经过在外层添加一个<ng-container>来解决

 

2.三、<ng-container> VS<ng-template> VS <ng-content>

<ng-container>渲染所包含的模板内容,不包含自身

<div>
    <ng-container>
        <span>Hello World!</span>
    </ng-container>
</div>

<!-- 实际渲染结果是 -->
<div>
    <span>Hello World!</span>
</div>

<ng-template>它不会直接渲染任何内容,主要是配合其余的结构型指令一块儿使用

<ng-template>
    <span>Hello World!</span>
</ng-template>

<!-- 默认不会渲染任何内容 -->

<ng-content>使得这个组件能接收外部投射进来的内容,也就是说组件最终呈现的内容不只仅是自己定义的那些。

父组件在调用子组件时,还能够在子组件里添加内容,而后在子组件中使用<ng-content>显示那部份内容到该处。

//父组件中调用子组件 app-with-title
<app-with-title>
    <div>hello</div>
    <div>world</div>
</app-with-title>
//子组件
<div>title</div>
<ng-content></ng-content>

// 子组件实际渲染的结果是
<div>title</div>
<div>hello</div>
<div>world</div>

2.四、ng-container 只会展现包含的内容

下面的实例,很好的展现了 ng-container 的用法;需求是只展现奇数的数据,若是是同时使用 ngFor 和 ngIf 会报错

<ul>
    <li *ngFor="let item of list; let odd = odd" * ngIf="odd">
        {{ item }}
    </li>
</ul>

会报错,*开头的指令,一个元素只能使用一次

<ul>
    <ng-container *ngFor="let item of list; let odd = odd">
        <li *ngIf="odd">{{ item }}</li>
    </ng-container>
</ul>

2.五、*ngTemplateOutlet

<ng-template #data>
    Hello World
</ng-template>

<div *ngTemplateOutlet="data"></div>

相似 angularJS 里面的 include,加载对应的模块代码块,不过更强大,像是调用一个函数,能够传参

在使用 *ngTemplateOutlet 的时候,能够加上 context 表明要传入 ng-template 的参数,好比

<div *ngTemplateOutlet="data; context: {$implicit: {value: 1}}"></div>
//这个 $implicit 是一个固定用法,就像es6 module中的export default同样, $implicit 后面的值,会被当作传入 ng-template 的默认参数

//在 ng-template 里只须要使用 let-xxx 的方式,就能够接收到这个传入的默认参数
<ng-template #data let-xxx>
  {{ xxx | json }}
</ng-template>

<div *ngTemplateOutlet="data; context: {$implicit: {value: 1}}"></div>
//使用 let-xxx,ng-template 內部就有一个 xxx 变量,这里 xxx 的值就是 {value : 1}

ng-template 传入多个参数

$implicit 的方式实际上就是 let-xxx="$implicit",若是有多个参数须要传入,能够这样:

<ng-template #data let-xxx let-another="another">
    <div>{{ xxx | json }}</div>
    <div>{{ another | json }}</div>
</ng-template>

<div
    *ngTemplateOutlet="data; context: {$implicit: {value: 1}, another: {value: 2}}"
></div>

 

 

 

三、获取用户数据的方式:

使用Angular的模板引用变量,这些变量提供了从模板中直接访问元素的能力,在标识符前加上井号# 就能直接声明一个模板引用变量了。

<input #box/>
<p>{{box.value}}</p>

//按键事件过滤
<input #box (keyup.enter)="onEnter(box.value)"/>
onkey(value:string){
  this.value=value;
}

经过$event对象取得用户输入

<input (keyup)="onkey($event)"/>
onkey(event:any){
    this.value=event.target.value;
}

可是经过$event是靠不住的作法,反对把整个dom事件传入方法中,由于这样组件会知道太多模板的信息,这样就违反了模板和组件之间的分离关注原则了。

 

四、组件间的交互的方式

(1)父---->子

子组件若接收来自父组件传入的消息,必须定义一个输入属性,该属性经过Input装饰器修饰的。

//子组件  child.ts
@Input() private message:string;
//父组件 html
<child [message]="msgToChild"></child>

(2)子----->父

经过输出接口完成

//子组件 child.ts
@Output() private outer=new EventEmitter<string>();
sendToParent(){
    this.outer.emit('message from child');
}
//父组件
//. html
<child (outer)="recieve($event)"></child>     
//.ts    
private msgFromChild:string;
recieve($e:any){
    this.msgFromChild=$e;
}

(3)父子组件经过本地变量互动

父组件不能使用数据绑定来读取子组件的属性或调用子组件的方法,可是,能够在父组件的模板中,新建一个本地变量来表明子组件,而后利用这个变量来读取子组件的属性和调用子组件的方法。

//html文件
<child #children></child> //子组件 <button (click)="children.start()"></button>

(4)@viewChild()

两种用法:一、读取子组件

若是父组件的类须要读取子组件的值或方法,就不能使用本地变量的方法了。当父组件须要这种访问时,能够把子组件做为viewChild注入到父组件中

//html文件
<child></child> //子组件
<button (click)="start()"></button>
//ts文件
import { child} from './components/child.component';
@viewChild(child);
private sonComponent:child;
start(){
      this. sonComponent.start();
}

@viewChild()的另外一种用法:二、获取当前组件视图的单个元素

//.html
<input #name/>
//.ts
@viewChild('name') myName:ElementRef;
this.myName.nativeElement.focus();

 

五、路由

<router-outlet></router-outlet>把要显示在这个出口处的组件显示在这里。

路由跳转

<a routerLink="/heroes" routerLinkActive="active">Heroes</a>
<a routerLink="['/heroes']">Heroes</a>
<a routerLink="[/home]"+row.id>Heroes</a>//根据id跳转
//routerLinkActive表示当连接激活时添加“active”类

this.router.navigate(['/home']);  在ts文件中

 

根据参数跳转路由:

{
    path:'home/:id',
    component:HomeComponent    
}
//获取参数id
//(1)
constructor(private route:ActivatedRoute){
   route.params.subscribe(params=>{this.id=params['id']})
}
//(2)
constructor(private route:ActivatedRoute){}
const id=this.route.snapshot.paramMap.get('id');

 

六、管道

把数据做为输入,而后转换它,给出指望的输出。

<p>Hero`s birthdat is {{birthday | date}}</p>

让组件的birthday值经过管道操做符(|)流动到右侧的date管道函数中,全部管道都会用这种方式工做。

 

七、服务与依赖注入

为何要用服务?

一般须要对访问的数据作后处理、添加错误处理器,还可能加一些重试逻辑,以便应对网络问题。若是直接写在组件中,会由于这些数据方式的细节而变得杂乱不堪,组件变得难以理解,难以测试,而且这些数据访问逻辑没法被复用,也没法标准化,因此把数据展现逻辑与数据访问逻辑分开。

Angular把组件与服务区分开,以提升模块性和复用性。经过把组件中和视图相关的功能与其余类型的处理分离开,可使组件类更精简、高效。

组件应该把诸如从服务器获取数据、验证用户输入等工做委托给服务。

依赖注入:是组件引入外部构建(如服务)的一种机制。

相关文章
相关标签/搜索