Angular 組件樣式

2022-06-29 10:11 更新

組件樣式

Angular 應(yīng)用使用標(biāo)準(zhǔn)的 CSS 來設(shè)置樣式。這意味著你可以把關(guān)于 CSS 的那些知識(shí)和技能直接用于 Angular 程序中,例如:樣式表、選擇器、規(guī)則以及媒體查詢等。

另外,Angular 還能把組件樣式捆綁在組件上,以實(shí)現(xiàn)比標(biāo)準(zhǔn)樣式表更加模塊化的設(shè)計(jì)。

本章將會(huì)講解如何加載和使用這些組件樣式

可以運(yùn)行現(xiàn)場(chǎng)演練 / 下載范例,在 Stackblitz 中試用并下載本頁(yè)的代碼。

使用組件樣式

對(duì)你編寫的每個(gè) Angular 組件來說,除了定義 HTML 模板之外,還要定義用于模板的 CSS 樣式、 指定任意的選擇器、規(guī)則和媒體查詢。

實(shí)現(xiàn)方式之一,是在組件的元數(shù)據(jù)中設(shè)置 ?styles ?屬性。 ?styles ?屬性可以接受一個(gè)包含 CSS 代碼的字符串?dāng)?shù)組。 通常你只給它一個(gè)字符串就行了,如同下例:

@Component({
  selector: 'app-root',
  template: `
    <h1>Tour of Heroes</h1>
    <app-hero-main [hero]="hero"></app-hero-main>
  `,
  styles: ['h1 { font-weight: normal; }']
})
export class HeroAppComponent {
/* . . . */
}

范圍化的樣式

在 ?@Component? 的元數(shù)據(jù)中指定的樣式只會(huì)對(duì)該組件的模板生效。

它們既不會(huì)被模板中嵌入的組件繼承,也不會(huì)被通過內(nèi)容投影(如 ng-content)嵌進(jìn)來的組件繼承。

在這個(gè)例子中,?h1? 的樣式只對(duì) ?HeroAppComponent ?生效,既不會(huì)作用于內(nèi)嵌的 ?HeroMainComponent?,也不會(huì)作用于應(yīng)用中其它任何地方的 ?<h1>? 標(biāo)簽。

這種范圍限制就是所謂的樣式模塊化特性

  • 可以使用對(duì)每個(gè)組件最有意義的 CSS 類名和選擇器。
  • 類名和選擇器是局限于該組件的,它不會(huì)和應(yīng)用中其它地方的類名和選擇器沖突。
  • 組件的樣式不會(huì)因?yàn)閯e的地方修改了樣式而被意外改變。
  • 可以讓每個(gè)組件的 CSS 代碼和它的 TypeScript、HTML 代碼放在一起,這將促成清爽整潔的項(xiàng)目結(jié)構(gòu)。
  • 以后還可以修改或移除組件的 CSS 代碼,而不用遍歷整個(gè)應(yīng)用來看它有沒有在別處用到。

特殊的選擇器

組件樣式中有一些從影子(Shadow) DOM 樣式范圍領(lǐng)域(記錄在W3CCSS Scoping Module Level 1中) 引入的特殊選擇器

:host

每個(gè)組件都會(huì)關(guān)聯(lián)一個(gè)與其組件選擇器相匹配的元素。這個(gè)元素稱為宿主元素,模板會(huì)渲染到其中。?:host? 偽類選擇器可用于創(chuàng)建針對(duì)宿主元素自身的樣式,而不是針對(duì)宿主內(nèi)部的那些元素。

@Component({
  selector: 'app-main',
  template: `
      <h1>It Works!</h1>
      <div>
        Start editing to see some magic happen :)
      </div>
  `
})
export class HostSelectorExampleComponent {

}

下面的樣式將以組件的宿主元素為目標(biāo)。應(yīng)用于此選擇器的任何規(guī)則都將影響宿主元素及其所有后代(在這種情況下,將所有包含的文本斜體)。(譯注:后代的樣式源自 CSS 的樣式繼承特性)

:host {
  font-style: italic;
}

?:host? 選擇是是把宿主元素作為目標(biāo)的唯一方式。除此之外,你將沒辦法指定它, 因?yàn)樗拗鞑皇墙M件自身模板的一部分,而是父組件模板的一部分。

要把宿主樣式作為條件,就要像函數(shù)一樣把其它選擇器放在 ?:host? 后面的括號(hào)中。

在這個(gè)例子中,當(dāng) CSS 類 ?active ?應(yīng)用在宿主元素上時(shí),宿主元素的內(nèi)容也變成了粗體。

:host {
  font-style: italic;
}

:host(.active) {
  font-weight: bold;
}

?:host? 選擇器也可以與其他選擇器組合使用。在 ?:host? 后面添加選擇器以選擇子元素,例如,使用 ?:host h2? 定位組件視圖內(nèi)的 ?<h2>?。

不應(yīng)該在 ?:host? 選擇器前面添加除 ?:host-context? 之外的選擇器來試圖基于組件視圖的外部上下文為本組件設(shè)置樣式。因?yàn)榇祟愡x擇器的作用域不會(huì)限于組件的視圖,而是會(huì)選擇外部上下文,但這不是內(nèi)置的行為。請(qǐng)改用 ?:host-context? 選擇器。

:host-context

有時(shí)候,需要以某些來自宿主的祖先元素為條件來決定是否要應(yīng)用某些樣式。 例如,在文檔的 ?<body>? 元素上可能有一個(gè)用于表示樣式主題 (theme) 的 CSS 類,你應(yīng)當(dāng)基于它來決定組件的樣式。

這時(shí)可以使用 ?:host-context()? 偽類選擇器。它也以類似 ?:host()? 形式使用。它在當(dāng)前組件宿主元素的祖先節(jié)點(diǎn)中查找 CSS 類, 直到文檔的根節(jié)點(diǎn)為止。它只能與其它選擇器組合使用。

在下面的例子中,只有當(dāng)該組件的某個(gè)祖先元素有 CSS 類 ?active ?時(shí),才會(huì)把該組件內(nèi)部的所有文本置為斜體。

:host-context(.active) {
  font-style: italic;
}

注意,只有宿主元素及其各級(jí)子節(jié)點(diǎn)會(huì)受到影響,不包括加上 ?active ?類的這個(gè)節(jié)點(diǎn)的祖先。

已棄用 /deep/、>>> 和 ::ng-deep

組件樣式通常只會(huì)作用于組件自身的 HTML 上。

把偽類 ?::ng-deep? 應(yīng)用到任何一條 CSS 規(guī)則上就會(huì)完全禁止對(duì)那條規(guī)則的視圖包裝。任何帶有 ?::ng-deep? 的樣式都會(huì)變成全局樣式。為了把指定的樣式限定在當(dāng)前組件及其下級(jí)組件中,請(qǐng)確保在 ?::ng-deep? 之前帶上 ?:host? 選擇器。如果 ?::ng-deep? 組合器在 ?:host? 偽類之外使用,該樣式就會(huì)污染其它組件。

這個(gè)例子以所有的 ?<h3>? 元素為目標(biāo),從宿主元素到當(dāng)前元素再到 DOM 中的所有子元素:

:host ::ng-deep h3 {
  font-style: italic;
}

?/deep/? 組合器還有兩個(gè)別名:?>>>? 和 ?::ng-deep?。

?/deep/? 和 ?>>>? 選擇器只能被用在仿真 (emulated) 模式下。 這種方式是默認(rèn)值,也是用得最多的方式。

CSS 標(biāo)準(zhǔn)中用于 "刺穿 Shadow DOM" 的組合器已經(jīng)被棄用,并將這個(gè)特性從主流瀏覽器和工具中移除。 因此,我們也將在 Angular 中移除對(duì)它們的支持(包括 ?/deep/?、?>>>? 和 ?::ng-deep?)。 目前,建議先統(tǒng)一使用 ?::ng-deep?,以便兼容將來的工具。

把樣式加載進(jìn)組件中

有幾種方式把樣式加入組件:

  • 設(shè)置 ?styles ?或 ?styleUrls ?元數(shù)據(jù)
  • 內(nèi)聯(lián)在模板的 HTML 中
  • 通過 CSS 文件導(dǎo)入

上述作用域規(guī)則對(duì)所有這些加載模式都適用。

元數(shù)據(jù)中的樣式

給 ?@Component? 裝飾器添加一個(gè) ?styles ?數(shù)組型屬性。

這個(gè)數(shù)組中的每一個(gè)字符串(通常也只有一個(gè))定義一份 CSS。

@Component({
  selector: 'app-root',
  template: `
    <h1>Tour of Heroes</h1>
    <app-hero-main [hero]="hero"></app-hero-main>
  `,
  styles: ['h1 { font-weight: normal; }']
})
export class HeroAppComponent {
/* . . . */
}

注意:這些樣式只對(duì)當(dāng)前組件生效。 它們既不會(huì)作用于模板中嵌入的任何組件,也不會(huì)作用于投影進(jìn)來的組件(如 ?ng-content? )。

當(dāng)使用 ?--inline-styles? 標(biāo)識(shí)創(chuàng)建組件時(shí),Angular CLI 的 ?ng generate component? 命令就會(huì)定義一個(gè)空的 ?styles ?數(shù)組

ng generate component hero-app --inline-style

組件元數(shù)據(jù)中的樣式文件

把外部 CSS 文件添加到 ?@Component? 的 ?styleUrls ?屬性中以加載外部樣式。

  • src/app/hero-app.component.ts (CSS in file)
  • @Component({
      selector: 'app-root',
      template: `
        <h1>Tour of Heroes</h1>
        <app-hero-main [hero]="hero"></app-hero-main>
      `,
      styleUrls: ['./hero-app.component.css']
    })
    export class HeroAppComponent {
    /* . . . */
    }
  • src/app/hero-app.component.css
  • h1 {
      font-weight: normal;
    }

注意:這些樣式只對(duì)當(dāng)前組件生效。 它們既不會(huì)作用于模板中嵌入的任何組件,也不會(huì)作用于投影進(jìn)來的組件(如 ?ng-content? )。

你可以指定多個(gè)樣式文件,甚至可以組合使用 ?style ?和 ?styleUrls ?方式。

當(dāng)你使用 Angular CLI 的 ?ng generate component? 命令但不帶 ?--inline-style? 標(biāo)志時(shí),CLI 會(huì)為你創(chuàng)建一個(gè)空白的樣式表文件,并且在所生成組件的 ?styleUrls ?中引用該文件。

ng generate component hero-app

模板內(nèi)聯(lián)樣式

可以直接在組件的 HTML 模板中寫 ?<style>? 標(biāo)簽來內(nèi)嵌 CSS 樣式。

@Component({
  selector: 'app-hero-controls',
  template: `
    <style>
      button {
        background-color: white;
        border: 1px solid #777;
      }
    </style>
    <h3>Controls</h3>
    <button (click)="activate()">Activate</button>
  `
})

模板中的 link 標(biāo)簽

你也可以在組件的 HTML 模板中寫 ?<link>? 標(biāo)簽。

@Component({
  selector: 'app-hero-team',
  template: `
    <!-- We must use a relative URL so that the AOT compiler can find the stylesheet -->
    <link rel="stylesheet" href="../assets/hero-team.component.css">
    <h3>Team</h3>
    <ul>
      <li *ngFor="let member of hero.team">
        {{member}}
      </li>
    </ul>`
})
當(dāng)使用 CLI 進(jìn)行構(gòu)建時(shí),要確保這個(gè)鏈接到的樣式表文件被復(fù)制到了服務(wù)器上。
只要引用過,CLI 就會(huì)計(jì)入這個(gè)樣式表,無論這個(gè) link 標(biāo)簽的 href 指向的 URL 是相對(duì)于應(yīng)用根目錄的還是相對(duì)于組件文件的。

CSS @imports 語法

可以利用標(biāo)準(zhǔn)的 CSS @import 規(guī)則來把其它 CSS 文件導(dǎo)入到 CSS 文件中。

這種情況下,URL 是相對(duì)于你正在導(dǎo)入的 CSS 文件的。

/* The AOT compiler needs the `./` to show that this is local */
@import './hero-details-box.css';

外部以及全局樣式文件

當(dāng)使用 CLI 進(jìn)行構(gòu)建時(shí),你必須配置 ?angular.json? 文件,使其包含所有外部資源(包括外部的樣式表文件)。

在它的 ?styles ?區(qū)注冊(cè)這些全局樣式文件,默認(rèn)情況下,它會(huì)有一個(gè)預(yù)先配置的全局 ?styles.css? 文件。

非 CSS 樣式文件

如果使用 CLI 進(jìn)行構(gòu)建,那么你可以用 sass 或 less 來編寫樣式,并使用相應(yīng)的擴(kuò)展名(?.scss?、?.less?)把它們指定到 ?@Component.styleUrls? 元數(shù)據(jù)中。例子如下:

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.scss']
})
...

CLI 的構(gòu)建過程會(huì)運(yùn)行相關(guān)的預(yù)處理器。

當(dāng)使用 ?ng generate component? 命令生成組件文件時(shí),CLI 會(huì)默認(rèn)生成一個(gè)空白的 CSS 樣式文件(?.css?)。 你可以配置 CLI,讓它默認(rèn)使用你喜歡的 CSS 預(yù)處理器。

添加到 ?@Component.styles? 數(shù)組中的字符串必須寫成 CSS,因?yàn)?nbsp;CLI 沒法對(duì)這些內(nèi)聯(lián)的樣式使用任何 CSS 預(yù)處理器。


以上內(nèi)容是否對(duì)您有幫助:
在線筆記
App下載
App下載

掃描二維碼

下載編程獅App

公眾號(hào)
微信公眾號(hào)

編程獅公眾號(hào)