【2020-01-23】组件与模板 -- 模板语法
绑定语法
1、从数据源到视图
{{expression}}
[target] = "expression"
bind-target = "expression"
2、从视图到数据源的单向绑定
(target)= "statement"
on-target = "statement"
3、双向
[(target)] = "expression"
bindon-target = "expression"
HTML attribute DOM property
--attribute值不能改变,但是property的值可以改变
<input type="text" value="Bob">
创建DOM节点,且它的value的property被初始化为Bob
当用户输入“sal”,Dom元素的property变成了sal,但是该HTML的attribute仍是Bob保持不变
disabled 是HTML的attribute,其property值默认是false,当添加这个disabled attribute时,disabled的property会自动初始化为true
所以禁用或者启动按钮,与attribute的值无关
<button [disabled]="isUnchanged">Save</button>
这里设置的是disabled的property值
模板绑定是通过property和事件来工作的,而不是attribute
4、绑定目标
数据绑定的目标是DOM中的某些东西,这个目标可能是元素|组件|指令的 property/事件等
①属性
②事件
③双向
④Attribute
⑤CSS类
⑥样式
属性绑定
[属性名] -- 最常用的属性绑定就是把元素属性设置为组件属性的值
属性名是property的名字 或者已知指令的属性名
当名字没有匹配上已知指令或元素的属性,Angular就会报告“未知指令”的错误
一次性字符串优化
当满足下列条件时,应该省略括号:
1、目标属性接受字符串值
2、字符串是个固定值,可以直接合并到模板中
3、这个初始值永不改变
prefix属性值满足上面条件,所以可以省略方括号
当数据类型是字符串,可以用数据绑定[],也可以用插值{{}}
当数据类型不是字符串,只能用数据绑定[]
attribute,class, style绑定
1、attribute 绑定
当元素没有属性(property)可绑的时候,就必须使用attribute绑定
<tr><td colspan="{{1 + 1}}">Three-Four</td></tr> //会报错,因为colspan不属于property,但插值和数据绑定只能设置property,所以需要attribute来创建和绑定这样的attribute
<tr><td [attr.colspan]="1 + 1">Three-Four</td></tr>
2、CSS类绑定 -- 添加或者移除class 属性
①直接绑定
②使用数据绑定 :
// test属性的值会覆盖原本设置的 bad curly special , class属性最终为test属性的值
③绑定到特定的类名,当模板表达式的求值结果为真,则Angular会添加这个类
此绑定方式不会影响原来已有的class名
// 若是有多个class名,则一般通过[NgClass]管理
3、样式绑定
通过样式绑定,可以设置内联样式
isSpecial 和canSave都是组件属性
有些样式绑定中的样式带有单位
// 若是设置多个内联样式,可以用[NgStyle]指令
事件绑定
事件绑定允许你侦听某些事件,比如按键,鼠标移动,点击和触屏
目标事件
如果这个名字没有匹配到元素事件或者已知指令的输出属性,Angular则会报“未知指令”错误
$ event 和事件处理语句
当事件发生时,这个处理器会执行模板语句。典型的模板语句通常涉及到响应事件执行动作的接收器,例如从HTML控件中取得值,并存入模型。
绑定会通过名叫$event的事件对象传递关于此事件的信息(包括数据)
事件对象的形态取决于目标事件,如果目标事件是原生DOM元素事件,$event 就是DOM事件对象,他有像target和target.value这样的属性
上面case中,把输入框的value属性绑定到name属性,要监听对值的修改,代码绑定到输入框的input事件。当用户造成更改时,input事件被触发,并在包含了DOM事件对象($event)的上下文中执行这条语句
要更新name属性,就要通过$event.target.value来获取更改后的值
使用EventEmitter实现自定义事件
通常指令使用angular EventEmitter来触发自定义事件。指令创建一个EventEmitter 实例,并且把它作为属性暴露出来。指令调用EvenetEmitter.emit(payload)来触发事件,可以传入任何东西作为消息载荷
父指令通过绑定到这个属性来监听事件,并通过$event对象来访问载荷
双向绑定
1、双向绑定的基础知识:
双向绑定会做两件事:
①设置特定的元素属性
②监听元素的变更事件
angular为此提供了一种特殊的双向数据绑定语法[()] ,将属性绑定的[]与事件绑定的()组合在一起
内置指令
Angular提供了两种内置指令:属性型指令和结构型指令
1、内置属性型指令
属性型指令会监听并修改其他HTML元素和组件的行为、Attribute和Property.他们通常被应用在元素上,好像它们是HTML属性一样,因此得名属性型指令
常见的属性型指令如下:
NgClass -添加和删除一组CSS类型,如果只对一个CSS类操作请用类绑定
NgStyle - 添加和删除一组HTML样式,如果只对一个样式操作请用样式绑定
NgModel - 将数据双向绑定添加到HTML表单元素
2、内置结构型指令
结构型指令的职责是HTML布局,它们塑造或重塑造DOM结构,这通常是通过添加、移除、和操纵它们所附加的宿主元素来实现的
常见的内置结构型指令:
NgIf - 从模板中创建或销毁子视图
NgFor - 为列表中的每个条目重复渲染一个节点
NgSwitch - 一组在备用视图之间切换的指令
注意:隐藏元素时,该元素以及后代仍保留在DOM中。这些元素的所有组件都保留在内存中,Angular会继续做变更检查。它可能会占用大量的资源,并且不必要降低性能
①NgIf工作方式有所不同。如果NgIf为false,则Angular将从DOM中删除该元素及其后代。这销毁了它们的组件,释放了资源,从而带来更好的用户体验
如果要隐藏大型组件树,请考虑使用NgIf作为显示、隐藏的更有效替代方法
NgIf另一个优点就是您可以使用它来防范空指针错误。
②带trackBy的*ngFor --可以提升性能
如果ngFor循环的数组需要改变(大量的新增或者删除元素),若是不带有trackBy,则所有的DOM元素会被重新刷新
若是带了trackBy --指定需要跟踪的对象,则只有跟踪的对象发生变化时才会刷新对应的DOM元素,提升性能
模板引用变量
模板引用变量(#var)
模板引用变量通常是对模板中DOM元素的引用。它还可以引用指令(包含组件)、元素、TemplateRef 或Web Component
使用#声明模板引用变量
模板引用变量的范围是整个模板
输入和输出属性
@Input --允许将数据从负责建输入到子组件中
注意:要监视@Input()属性的更改,OnChanges是专门设计用于具有@Input()装饰器的属性
@OutPut -- 指的是事件从组件中向外流出,属性类型是EventEmitter
使用@Input()/ @OutPut()装饰器指定别名
别名size2是在父组件中 【子组件指令中使用】
模板表达式中的运算符
1、管道
在准备将用于绑定之前,表达式的结果可能需要进行一些转换。例如,您可以将数组显示为货币,将文本更改为大写,或过滤列表并对其进行排序
管道是简单的函数。它们接受输入值并返回转换后的值。使用管道运算,很容易在模板表达式中使用它们
<p>Title through uppercase pipe: {{title | uppercase}}</p>
<p>Item json pipe: {{item | json}}</p> // json pipe可以将json对象转为json格式的字符串
管道运算符的优先级比三元运算符(?:)高,这意味着a ? b: c | x 将被解析为
a ? b : (c | x) .
2、安全导航运算符
Angular 安全导航运算符?可以对在属性路径中出现null和undefined值进行保护
<p>The item name is: {{item?.name}}</p>
在这里,如果item为null,它可以防止视图渲染失败,即:视图仍然渲染,但显示的值仍是空白,会占据位置
3、非空断言运算符(!)
<!--No color, no error -->
<p *ngIf="item">The item's color is: {{item!.color}}</p>
内置模板函数
类型转换函数 $any()
<p>The item's undeclared best by date is: {{$any(item).bestByDate}}</p>
$any()转换函数可以和thisi联合使用,以便访问组件中未声明的成员
<p>The item's undeclared best by date is: {{$any(this).bestByDate}}</p>
//tips
JS加载包括预编译和执行两个阶段
预编译阶段会对所有var变量和function进行扫描,并将变量初始化为undefined类型,而function则被初始化为函数值
到了执行阶段,JS从上面往下面依顺序执行,遇到var变量进行赋值(因此,在赋值之前进行调用的话会出现错误的)