语句上下文
和表达式中一样,语句只能引用语句上下文中 —— 通常是正在绑定事件的那个组件实例。
As with expressions, statements can refer only to what's in the statement context such as an event handling method of the component instance.
典型的语句上下文就是当前组件的实例。 (click)="deleteHero()"
中的 deleteHero 就是这个数据绑定组件上的一个方法。
src/app/app.component.html
content_copy<button (click)="deleteHero()">Delete hero</button>
语句上下文可以引用模板自身上下文中的属性。 在下面的例子中,就把模板的 $event
对象、模板输入变量 (let hero
)和模板引用变量 (#heroForm
)传给了组件中的一个事件处理器方法。
src/app/app.component.html
content_copy<button (click)="onSave($event)">Save</button>
<button *ngFor="let hero of heroes" (click)="deleteHero(hero)">{{hero.name}}</button>
<form #heroForm (ngSubmit)="onSubmit(heroForm)"> ... </form>
模板上下文中的变量名的优先级高于组件上下文中的变量名。在上面的 deleteHero(hero)
中,hero
是一个模板输入变量,而不是组件中的 hero
属性。
Template context names take precedence over component context names. In deleteHero(hero)
above, the hero
is the template input variable, not the component's hero
property.
模板语句不能引用全局命名空间的任何东西。比如不能引用 window
或 document
,也不能调用 console.log
或 Math.max
。
数据绑定
绑定的类型可以根据数据流的方向分成三类: 从数据源到视图、从视图到数据源以及双向的从视图到数据源再到视图。
Binding types can be grouped into three categories distinguished by the direction of data flow: from the source-to-view, from view-to-source, and in the two-way sequence: view-to-source-to-view:
数据方向 | 语法 | 绑定类型 |
---|---|---|
单向 | content_copy | 插值表达式 |
从视图到数据源的单向绑定 | content_copy | 事件 |
双向 | content_copy | 双向 |
现在开始学习数据绑定。你碰到的第一种数据绑定是这样的:
src/app/app.component.html
content_copy<!-- Bind button disabled state to `isUnchanged` property -->
<button [disabled]="isUnchanged">Save</button>
过会儿再认识那个怪异的方括号记法。直觉告诉你,你正在绑定按钮的 disabled
attribute。 并把它设置为组件的 isUnchanged
属性的当前值。
但你的直觉是错的!日常的 HTML 思维模式在误导着你。 实际上,一旦开始数据绑定,就不再跟 HTML attribute 打交道了。 这里不是设置 attribute,而是设置 DOM 元素、组件和指令的 property。
HTML attribute 与 DOM property 的对比
要想理解 Angular 绑定如何工作,重点是搞清 HTML attribute 和 DOM property 之间的区别。
attribute 是由 HTML 定义的。property 是由 DOM (Document Object Model) 定义的。
-
少量 HTML attribute 和 property 之间有着 1:1 的映射,如
id
。 -
有些 HTML attribute 没有对应的 property,如
colspan
。 -
有些 DOM property 没有对应的 attribute,如
textContent
。 -
大量 HTML attribute 看起来映射到了 property…… 但却不像你想的那样!
最后一类尤其让人困惑…… 除非你能理解这个普遍原则:
attribute 初始化 DOM property,然后它们的任务就完成了。property 的值可以改变;attribute 的值不能改变。
例如,当浏览器渲染 <input type="text" value="Bob">
时,它将创建相应 DOM 节点, 它的 value
这个 property 被初始化为 “Bob”。
当用户在输入框中输入 “Sally” 时,DOM 元素的 value
这个 property 变成了 “Sally”。 但是该 HTML 的 value
这个 attribute 保持不变。如果你读取 input 元素的 attribute,就会发现确实没变:input.getAttribute('value') // 返回 "Bob"
。
HTML 的 value
这个 attribute 指定了初始值;DOM 的 value
这个 property 是当前值。
disabled
这个 attribute 是另一种特例。按钮的 disabled
这个 property 是 false
,因为默认情况下按钮是可用的。 当你添加 disabled
这个 attribute 时,只要它出现了按钮的 disabled
这个 property 就初始化为 true
,于是按钮就被禁用了。
添加或删除 disabled
这个 attribute 会禁用或启用这个按钮。但 attribute 的值无关紧要,这就是你为什么没法通过 <button disabled="false">仍被禁用</button>
这种写法来启用按钮。
Adding and removing the disabled
attribute disables and enables the button. The value of the attributeis irrelevant, which is why you cannot enable a button by writing <button disabled="false">Still Disabled</button>
.
设置按钮的 disabled
这个 property(如,通过 Angular 绑定)可以禁用或启用这个按钮。 这就是 property 的价值。
就算名字相同,HTML attribute 和 DOM property 也不是同一样东西。
这句话值得再强调一次: 模板绑定是通过 property 和事件来工作的,而不是 attribute。
没有 ATTRIBUTE 的世界
在 Angular 的世界中,attribute 唯一的作用是用来初始化元素和指令的状态。 当进行数据绑定时,只是在与元素和指令的 property 和事件打交道,而 attribute 就完全靠边站了。
把这个思维模型牢牢的印在脑子里,接下来,学习什么是绑定目标