阅读(2706) (0)

Angular 属性(Attribute)、类、样式绑定

2022-06-28 10:41:53 更新

Attribute 绑定、类绑定和样式绑定

Angular 中的 Attribute 绑定可帮助你直接设置 Attribute 值。使用 Attribute 绑定,你可以提升无障碍性、动态设置应用程序样式以及同时管理多个 CSS 类或样式。

包含本指南中的代码片段的可工作示例,请参阅现场演练 / 下载范例

绑定到 Attribute

建议你尽可能设置带有 Property 绑定的元素的 Property。但是,有时你没有可绑定的元素 Property。在这种情况下,可以使用 Attribute 绑定。

例如,ARIASVG 只有 Attribute。 ARIA 和 SVG 都不对应于元素的 Property,也不设置元素的 Property。在这些情况下,必须使用 Attribute 绑定,因为没有相应的目标 Property。

语法

Attribute 绑定语法类似于 Property 绑定,但不是直接在方括号之间放置元素的 Property,而是在 Attribute 名称前面加上前缀 ​attr​,后跟一个点 ​.​。然后,使用解析为字符串的表达式设置 Attribute 值。

<p [attr.attribute-you-are-targeting]="expression"></p>

当表达式解析为 ​null ​或 ​undefined ​时,Angular 会完全删除该 Attribute。

绑定 ARIA Attribute

Attribute 绑定的主要用例之一是设置 ARIA Attribute,如下所示:

<!-- create and set an aria attribute for assistive technology -->
<button [attr.aria-label]="actionName">{{actionName}} with Aria</button>

绑定到 colspan

Attribute 绑定的另一个常见用例是绑定到表格中的 ​colspan ​Attribute。​colspan ​Attribute 可帮助你以编程方式让表格保持动态。根据应用中用来填充表的数据量,某一行要跨越的列数可能会发生变化。

要将 Attribute 绑定到 ​<td>​ 的 ​colspan ​Attribute:

  1. 使用以下语法指定 ​colspan​:​[attr.colspan]​ 。
  2. 将 ​[attr.colspan]​ 设置为等于某个表达式。

在下面的示例中,我们将 ​colspan ​Attribute 绑定到表达式 1 + 1

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

此绑定会导致 ​<tr>​ 跨越两列。

有时,Property 名和 Attribute 名之间存在差异。
colspan ​是 ​<tr>​ 的 Attribute,而 ​colSpan​(注意 “S” 是大写)是 Property。使用 Attribute 绑定时,请使用带小写 “s” 的 ​colspan​。

绑定到 class Attribute

可以用类绑定从元素的 ​class ​Attribute 中添加和删除 CSS 类名称。

绑定到单个 CSS class

要创建单个类绑定,请使用前缀 ​class ​后跟一个点和 CSS 类的名称,例如 ​[class.sale]="onSale"​。​onSale ​为真值时添加类,在表达式为假值时(​undefined ​除外)删除类。

绑定到多个 CSS 类

要绑定到多个类,请使用 ​[class]​ 来设置表达式 - 例如,​[class]="classExpression"​,此表达式可以取如下值:

  • 用空格分隔的类名字符串
  • 以类名作为键名并将真或假表达式作为值的对象。
  • 类名的数组。

对于对象格式,Angular 会在其关联的值为真时才添加类。

对于任何类似对象的表达式(例如 ​object​、​Array​、​Map ​或 ​Set​,必须更改对象的引用,Angular 才能更新类列表。在不更改对象引用的情况下只更新其 Attribute 是不会生效的。

如果同一类名有多个绑定,Angular 会根据样式优先级来确定要使用的绑定。

下表是各种类绑定语法的小结。

绑定类型

语法

输入类型

范例输入值

单一类绑定

[class.sale]="onSale" boolean | undefined | null truefalse

多重类绑定

[class]="classExpression" string "my-class-1 my-class-2 my-class-3"
Record<string, boolean | undefined | null> {foo: true, bar: false}
Array<string> ['foo', 'bar']

绑定到 style Attribute

可以用样式绑定来动态设置样式。

绑定到单一样式

要创建对单个样式的绑定,请使用前缀 ​style ​后跟一个点和 CSS style Attribute 的名称,例如 ​[style.width]="width"​。 Angular 会将该 Attribute 设置为绑定表达式的值,这个值通常是一个字符串。(可选)你还可以添加单位扩展,例如 ​em ​或 ​%​ ,它的值需要数字类型。

你可以用中线格式或 camelCase 格式编写样式 Attribute 名。

<nav [style.background-color]="expression"></nav>

<nav [style.backgroundColor]="expression"></nav>

绑定到多个样式

要切换多个样式,请绑定到 ​[style]​ Attribute,例如 ​[style]="styleExpression"​ 。​styleExpression ​可以是如下格式之一:

  • 样式的字符串列表,例如 ​"width: 100px; height: 100px; background-color: cornflowerblue;"​。
  • 一个对象,其键名是样式名,其值是样式值,比如 ​{width: '100px', height: '100px', backgroundColor: 'cornflowerblue'}​。

注意,不支持把数组绑定给 ​[style]​。

当把 ​[style]​ 绑定到对象表达式时,该对象的引用必须改变,这样 Angular 才能更新这个类列表。在不改变对象引用的情况下更新其属性值是不会生效的。

单样式和多样式绑定示例

@Component({
  selector: 'app-nav-bar',
  template: `
<nav [style]='navStyle'>
  <a [style.text-decoration]="activeLinkStyle">Home Page</a>
  <a [style.text-decoration]="linkStyle">Login</a>
</nav>`
})
export class NavBarComponent {
  navStyle = 'font-size: 1.2rem; color: cornflowerblue;';
  linkStyle = 'underline';
  activeLinkStyle = 'overline';
  /* . . . */
}

如果同一个样式 Attribute 有多个绑定,Angular 将使用样式优先级来确定要使用的绑定。

下表是各种样式绑定语法的小结。

绑定类型

语法

输入属性

范例输入值

单一样式绑定

[style.width]="width" string | undefined | null "100px"

带单位的单一样式绑定

[style.width.px]="width" number | undefined | null 100

多重样式绑定

[style]="styleExpression" string "width: 100px; height: 100px"
Record<string, string | undefined | null> {width: '100px', height: '100px'}

NgStyle​指令可以用作代替直接绑定 ​[style]​ 的方法。但是,最好使用上述不用 ​NgStyle ​的绑定语法,因为由于 Angular 中样式绑定的改进,​NgStyle ​不再提供显著价值,将来可能会被删除。

样式优先级

一个 HTML 元素可以将其 CSS 类列表和样式值绑定到多个源(例如,来自多个指令的宿主绑定)。

当有多个到相同的类名或样式属性的绑定时,Angular 使用一组优先规则来解决冲突并确定最终将哪些类或样式应用于元素。

样式优先级(从高到低)
  1. 模板绑定
    • 属性绑定(例如,​<div [class.foo]="hasFoo">​ 或 ​<div [style.color]="color">​ )
    • 映射表绑定(例如,​<div [class]="classExpr">​ 或 ​<div [style]="styleExpr">​ )
    • 静态值(例如 ​<div class="foo">​ 或 ​<div style="color: blue">​ )
  2. 指令宿主绑定
    • 属性绑定(例如,​host: {'[class.foo]': 'hasFoo'}​ 或 ​host: {'[style.color]': 'color'}​ )
    • 映射表绑定(例如,​host: {'[class]': 'classExpr'}​ 或 ​host: {'[style]': 'styleExpr'}​ )
    • 静态值(例如,​host: {'class': 'foo'}​ 或 ​host: {'style': 'color: blue'}​ )
  3. 组件宿主绑定
    • 属性绑定(例如,​host: {'[class.foo]': 'hasFoo'}​ 或 ​host: {'[style.color]': 'color'}​ )
    • 映射表绑定(例如,​host: {'[class]': 'classExpr'}​ 或 ​host: {'[style]': 'styleExpr'}​ )
    • 静态值(例如,​host: {'class': 'foo'}​ 或 ​host: {'style': 'color: blue'}​ )

总之,类或样式绑定越具体,其优先级就越高。

绑定到具体类(例如 ​[class.foo]​ )将优先于不特定 ​[class]​ 的绑定,并且绑定到特定样式(例如 ​[style.bar]​ )将优先于不特定 ​[style]​ 的绑定。

<h3>Basic specificity</h3>

<!-- The `class.special` binding overrides any value for the `special` class in `classExpression`.  -->
<div [class.special]="isSpecial" [class]="classExpression">Some text.</div>

<!-- The `style.border` binding overrides any value for the `border` property in `styleExpression`.  -->
<div [style.border]="border" [style]="styleExpression">Some text.</div>

当涉及不同来源的绑定时,也适用这些特异性规则。元素可能具有在其声明的模板中的绑定、在其匹配的指令中的宿主绑定、在其匹配的组件中的宿主绑定。

模板绑定是最具体的,因为它们会直接且排他地应用于元素,因此它们具有最高的优先级。

指令宿主绑定被认为不太具体,因为指令可以在多个位置使用,因此它们的优先级低于模板绑定。

指令通常会增强组件的行为,因此组件的宿主绑定具有最低的优先级。

<h3>Source specificity</h3>

<!-- The `class.special` template binding overrides any host binding to the `special` class set by `dirWithClassBinding` or `comp-with-host-binding`.-->

<comp-with-host-binding [class.special]="isSpecial" dirWithClassBinding></comp-with-host-binding>


<!-- The `style.color` template binding overrides any host binding to the `color` property set by `dirWithStyleBinding` or `comp-with-host-binding`. -->
<div>
  <comp-with-host-binding [style.color]="color" dirWithStyleBinding></comp-with-host-binding>
</div>

<h3>Dynamic vs static</h3>

<!-- If `classExpression` has a value for the `special` class, this value overrides the `class="special"` below -->
<div class="special" [class]="classExpression">Some text.</div>

<!-- If `styleExpression` has a value for the `border` property, this value overrides the `style="border: dotted darkblue 3px"` below -->
<div style="border: dotted darkblue 3px" [style]="styleExpression">Some text.</div>


<div class="readability">
  <comp-with-host-binding dirWithHostBinding></comp-with-host-binding>
</div>

<app-my-input-with-attribute-decorator type="number"></app-my-input-with-attribute-decorator>

此外,绑定会优先于静态属性。

在这里,​class ​和 ​[class]​ 具有相似的特异性,但是 ​[class]​ 绑定更优先一些,因为它是动态的。

<h3>Dynamic vs static</h3>

<!-- If `classExpression` has a value for the `special` class, this value overrides the `class="special"` below -->
<div class="special" [class]="classExpression">Some text.</div>

<!-- If `styleExpression` has a value for the `border` property, this value overrides the `style="border: dotted darkblue 3px"` below -->
<div style="border: dotted darkblue 3px" [style]="styleExpression">Some text.</div>

委托给优先级较低的样式

可以用 ​undefined ​值来把高优先级的样式“委托”给较低优先级的样式。将样式属性设置为 ​null ​可以确保样式被删除,而将其设置为 ​undefined ​将导致 Angular 回退到该样式的次高优先级绑定。

例如,考虑以下模板:

<comp-with-host-binding dirWithHostBinding></comp-with-host-binding>

假设 ​dirWithHostBinding ​指令和 ​comp-with-host-binding​ 组件都具有 ​[style.width]​ 宿主绑定。在这里,如果 ​dirWithHostBinding ​将其绑定设置为 ​undefined ​,则 ​width ​属性将回退到 ​comp-with-host-binding​ 宿主绑定的值。但是,如果 ​dirWithHostBinding ​将其绑定设置为 ​null ​,则会完全删除 ​width

注入属性值

在某些情况下,你需要根据在 host 元素上以 HTML 属性的形式设置的静态值来区分组件或指令的行为。例如,你可能有一个指令,需要知道 ​<button>​ 或 ​<input>​ 元素的 ​type ​值。

Attribute参数装饰器非常适合通过依赖注入来将 HTML 属性的值传递给组件/指令构造函数。

这里注入的值将捕获指定 HTML 属性的当前值。将来对属性值的修改不会反映到注入的值中。

import { Attribute, Component } from '@angular/core';

@Component({
  selector: 'app-my-input-with-attribute-decorator',
  template: '<p>The type of the input is: {{ type }}</p>'
})
export class MyInputWithAttributeDecoratorComponent {
  constructor(@Attribute('type') public type: string) { }
}
<app-my-input-with-attribute-decorator type="number"></app-my-input-with-attribute-decorator>

在前面的示例中,​app.component.html​的结果为:The type of the input is: number

另一个示例是RouterOutlet指令,该指令利用 Attribute 装饰器检索每个路由插座上的唯一名称。

@ATTRIBUTE() VS @INPUT()
请记住,要持续跟踪 Attribute 的值并更新关联的 Property 时,请使用 ​@Input()​。若要将 HTML 属性的值注入到组件或指令的构造函数中,请使用​@Attribute()​。