在使用angular/cli创建的新项目中,先将css的预编译器改为scss(将所有已.css为后缀的文件都改为.scss为后缀;同时将其他文件中对css文件的引用也都改为.scss)。随后导入bootstrap和font-awesome的依赖包(在package.json中添加这两个依赖包,然后运行cnpm install
命令即可)。随后可以做对应的语法测试。
插值语法
也就是典型的{{}}获取值的方法
如图,代码中声明变量和方法:
然后再html模板文件中使用:
最后显示的样子如下:
在模板内部定义局部变量
使用#符号,在html模板中定义局部变量,然后再html模板中使用。(组件类的ts代码中也是可以引用到的,但是需要使用到element-ref什么的,先不管)。
代码中声明:
html模板中使用#符号:
浏览器中显示:
值绑定、事件绑定、双向绑定
Angular 1.x的时候,数据绑定都是使用的model。但是在Angular 2中有区分:
- 值绑定:使用[]
- 事件绑定:使用()
- 双向绑定:使用[()]
单向值绑定
事件绑定
双向绑定
ngModel
ngModel可以用作数据绑定,但是只能用在表单元素上,类似于之类的添加一个ngModel指令就可以了。
使用[()]完成双向绑定
最后浏览器显示如下:子模块中文字字体大小变动可以同步到父组件中的文字 字体
首先,子组件中的代码如下:
然后,父组件中代码如下:使用子组件标签时,使用[()]将子组件类中的size属性双向绑定上父组件中的fontSizePx属性,然后子组件修改size之后,父组件的fontSizePx同步修改,做到双向数据绑定。
[()]补充:
上面没有写得很清楚,子控件在触发方法修改双重绑定的那个值时,需要将@Output中定义的对应”属性Change”事件进行emit。
下面是后面在网上查询到的:
那么,如何通过[()]在我们自定义的指令上实现双向绑定呢?没错,就是使用@Input和@Output来实现。
//父组件
@Component({
selector: 'my-app',
template: `
<customer-counter [(counter)] = "someValue"></customer-counter>
<p> value: {{someValue}}</p>
`,
directives:[CustomerCounterComponent]
})
export class AppComponent{
someValue = 3;
}
//子组件
@Component({
selector: 'customer-counter',
template: `
<button (click)="decrement()">-</button>
<span>{{counter}}</span>`
})
export class CustomerCounterComponent{
counterValue = 0;
@Input()
get counter(){
return this.counterValue;
}
@Output() counterChange = new EventEmitter();
set counter(val) {
this.counterValue = val;
// 这里,方法中需要在值改动的时候,将对应的值改变事件emit出去,让父组件能够接收到。
this.counterChange.emit(this.counterValue);
}
// 这个方法修改值,会调用值对应的setter方法(在setter方法中对事件进行了emit)
decrement() {
this.counter--;
}
}
这样<customer-counter [(counter)] = "someValue"></customer-counter>
就可以将父组件中的someValue绑定到子组件的counter属性上,同时当子组件的counter属性发生改变时也更新父组件的someValue值。
需要注意的是,我们定义的事件监听是counterChange,而使用的却是[(counter)]。
这是因为Angular 2中约定添加后缀Change,也就是[(counter)]等价于[change]和(counterChange)的组合。如果去看[(ngModel)]的实现,你也会发现它是[ngModel]和[ngModelChange]的组合。
内置结构型指令
结构型指令不可以在同一个标签中使用多个,只能用一个。解决方法就是多加一层div,用另一个指令。
*ngIf
<p *ngIf="isShow">是否显示</p>
*ngFor
*ngFor只能迭代数组,不能迭代一个对象中的属性。
<li *ngFor="let race of races;let i=index;">
{{i+1}}-{{race.name}}
</li>
ngSwitch
<div [ngSwitch]="mapStatus">
<p *ngSwitchCase="'下载中'">下载中...</p>
<p *ngSwitchCase="'正在读取'">正在读取...</p>
<p *ngSwitchDefault>系统繁忙</p>
</div>
内置属性型指令
NgClass
对应的css类会被加到对应的标签去,然后标签就有了这些类对应的样式。
<div [ngClass]="currentClasses">同时批量设置多个class</div>
<!--然后组件类中,设置currentClasses,设置为多个已经预先定义在scss文件中的类:-->
currentClasses = {
'saveable': this.canSave, // 后面这个值是一个bool,用来设置是否需要加上前面这个类
'modified': this.isUnchanged,
'special': this.isSpecial
};
NgStyle
与ngClass类似,但是ngStyle是直接写样式,而不是使用css类声明样式(这是不推荐的!)。使用方法也是一样的,在标签中对ngStyle使用值绑定到某个属性中:
<div [ngStyle]="currentStyles">
用ngStyle批量修改内联样式
</div>
<!--然后在组件类中,设置对应的变量,写对应的内联样式-->
currentStyles = {
'font-style': this.canSave ? 'italic' : 'normal',
'font-weight': this.isUnchanged ? 'bold' : 'normal',
'font-size': this.isSpecial ? '24px' : '12px'
};
NgModel
ngModel只能用在表单控件中,它是用来进行数据的双向绑定的,将ngModel使用[(ngModel)]双重数据绑定到组件类中的属性中即可:
<!--在组件类中声明属性-->
public currentRace: Any = {name: "随机种族"};
<!--在html模板中使用ngModel进行双向绑定-->
<input [(ngModel)]="currentRace.name">
<p>{{currentRace.name}}</p><!--这里就会随着input框的输入变化而变化,这就是双向数据绑定-->
需要使用ngModel的话,需要在app.module.ts这个应用根模块中import对应的表单模块才行,否则无法使用:
import {FormsModule} from '@angular/forms';
在imports节点中的数组中也添加上FormsModule
几个小工具
管道
管道是用来格式化字符串的,下面在页面中显示时间随着一秒一秒地跳动,同时使用管道将国际时间显示方式格式化为我们习惯的看法:
<!--首先在组件类中声明需要绑定的变量,然后设置变量一秒一变-->
export class TestPipeConponent implements OnInit {
public currentTime: Date = new Date();
construct() {
}
ngOnInit() {
// 在Init中每一秒钟给currentTime属性赋一个最新的值,让界面绑定的值会一秒一秒变动
window.setInterval(
// 这里使用了箭头函数,this指代了本类的实例,而不是指代本函数,这是箭头函数的好处
() => {this.currentTime = new Date()}
, 1000);
}
}
<!--然后在html模板中绑定上对应的属性,并且将属性使用管道进行格式化,date是系统内置的一个管道-->
<p>{{currentTiem | date:'yyyy-MM-dd HH:mm:ss'}}</p>
系统内置有12个管道:
自定义管道
需要自定义管道的话,要自定义类实现对应接口,如下
/**
** 新建boolean-pipe.ts文件
**/
import {Pipe, PipeTransform} from '@angular/core'; // import相关东西
// 使用装饰器,告诉angular编译器这是个Pipe
@Pipe({
name: 'boolean' // 名字是什么,后面使用这个管道的时候就用这个名字
})
// 类,需要实现PipeTransform,它又一个transform方法需要实现
export class BooleanPipe implements PipeTransform {
constructor() {
}
// 必须实现这个方法
transform(flag: string): string {
return flag==="true" ? "text-danger" : "";
}
}
/**
* 如何使用这个管道
**/
// 在需要使用这个管道的模块比如是post.module.ts文件中,import这个管道
import { BooleanPipe } from '../utils/boolean-pipe';
管道还有国际化的作用。
安全导航
安全导航就是一个语法糖,通过使用一个?,来告诉编译器,当我访问一个类的属性的时候,不管这个属性是否有定义,你都不要给我抛异常,如果属性未定义,你就直接不要显示就好了。
<p>当前选中的人种{{currentRace?.name}}</p>
<!--这种情况,如果在组件类中没有声明name这个属性的时候,angular编译器不会报错,而是会直接什么都不显示-->
非空断言
用得比较少