Sådan laver du et brugerdefineret tema i kantet materiale

Angular Material er et fantastisk bibliotek, der implementerer Material Design til Angular 2+. Det officielle dokument er tilstrækkeligt med hensyn til komponentbrug, mens der er få artikler om, hvordan man tilpasser selve temaet, specifikt de farver, der bruges i temaet.

I dette indlæg vil jeg gerne opsummere, hvad jeg har lært i disse måneder ved at tilpasse temaer i Angular Material.

Bemærk, at denne artikel IKKE handler om AngularJS-materiale, som bruges til AngularJS 1.x.

Relaterede indlæg

Nogle almindelige indlæg om tilpasning af temaer er:

  • "Theming your Angular Material app", den officielle guide til brugerdefinerede temaer,
  • “Den komplette guide til vinklede materialetemaer” af Tomas Trajan, som indeholder mange udokumenterede instruktioner. Stærkt anbefalet .

Jeg fandt ikke andre nyttige indlæg og ville sætte pris på, om nogen kunne give nogle ressourcer i kommentarerne.

Sådan oprettes et brugerdefineret tema

Oprettelse af et materielt tema er ekstremt enkelt: du behøver kun at vælge tre farver - primær , accent og advare - og Vinkelmateriale vil gøre resten for dig. Materialepaletsiden forklarer, hvordan det fungerer tydeligt, og du kan også oprette et tema visuelt med Color Tool.

Med hensyn til kode er alt hvad du skal gøre, at oprette følgende temafil:

// [email protected] '[email protected]/material/theming';
$my-theme-primary: mat-palette($mat-green);$my-theme-accent : mat-palette($mat-amber);$my-theme-warn : mat-palette($mat-red);
$my-theme: mat-light-theme( $my-theme-primary, $my-theme-accent, $my-theme-warn);

Derefter skal du anvende dette tema i din hovedfil style.scss:

@import "theme.scss";
@include mat-core();@include angular-material-theme($my-theme);

Sådan bruges brugerdefineret tema i komponenter

Efter at have oprettet vores eget tema vil krav som dette stige:

Jeg vil oprette et tekstfelt. Tekstfarve, baggrundsfarve og kantfarve skal alle komme fra vores eget tema, ikke ved hård kodning.

Dette krav er ret almindeligt - alligevel er det nøjagtigt, hvorfor vi vil oprette et brugerdefineret tema, at kunne bruges i komponenter. Problemet er hvordan.

Mixin-tilgangen

Det første officielle dokument, jeg delte, foreslog en måde at bruge SCSS's mixin på. Jeg kalder det en ”bottom-up” tilgang, der inkluderer følgende trin:

  1. Hver komponent definerer et temamixin og henter farver fra $themeparameteren.
  2. Et globalt theme.scssdefinerer det brugerdefinerede tema og inkluderer derefter alle komponenttema mixins og kalder dem med det tilpassede tema.

Ud over den theme.scssovennævnte definition skal hver komponent oprette en temafil som denne:

// src/app/comp-a/[email protected] '[email protected]/material/theming';
@mixin comp-a-theme($theme) { // define mixin $primary: map-get($theme, primary); // retrieve color def button { // apply theme to component background-color: mat-color($primary); }}

Og sandsynligvis vil du have en custom-theme.scsstil at importere alle temaerne på komponentniveau:

// src/app/[email protected] '[email protected]/material/theming';@import 'src/app/comp-a/comp-a.theme';@import 'src/app/comp-b/comp-b.theme';
@mixin custom-themes($theme) { @include comp-a-theme($theme); @include comp-b-theme($theme);}

Importér derefter ovenstående custom-theme.scssi din theme.scss:

// [email protected] './custom-theme';@include custom-themes($my-theme);

Dette hierarki fungerer og er sandsynligvis den eneste måde, hvorpå du har brug for at understøtte flere temaer .

Men det meste af tiden understøtter vi kun et tema, og det kan være besværligt at bruge en mixin. Der er primært tre ulemper ved denne tilgang:

  1. Hver enkelt farvehenvisning har brug for en separat .theme.scssfil.
  2. custom-theme.scssskal vide nøjagtigt, hvilke komponenter der leverer brugerdefinerede temaer. Dette skaber unødvendige afhængigheder.
  3. Vigtigst er det, at temafiler på komponentniveau ikke er indkapslet.

Det første og andet punkt er ret selvforklarende. Lad mig forklare lidt om punkt 3. Dette involverer noget baggrundsviden kaldet “View Encapsulation”.

Angular bruger en teknik kaldet "View Encapsulation" for at holde komponent CSS lokal. Med andre ord forbliver regler, der er defineret for en komponent, i den pågældende komponent og påvirker ikke andre komponenter.

På denne måde kan du definere CSS-klassenavn frit i din komponent uden at bekymre dig om navngivning af konflikter. Dog udsigt indkapsling er gjort, kun hvis CSS er defineret igennem @Component, det vil sige @Component({ styleUrls: ['./comp-a.scss'] }).

Med hensyn til vores brugerdefinerede temafil comp-a.theme.scss, da den importeres direkte af custom-theme.scss, er dens regler ikke indkapslet, så den gælder for alle elementer på siden. I eksemplet ovenfor brugte jeg følgende kode (som var forkert!):

@mixin comp-a-theme($theme) { button { ... } // This will apply to ALL buttons!}

Men dette vil anvende stilen på alle knapper i stedet for de knapper, der comp-akun tilhører . Du er nødt til at gøre noget lignende comp-a buttonfor at få dette til at fungere korrekt.

Den direkte tilgang

Derfor foreslår jeg en bedre tilgang. I stedet for at bruge et mixin lader vi hver komponent omfatte temafilen og bruger farvedefinitionen direkte.

I denne tilgang vil komponenttema-filen se sådan ud:

// NOTE: just do this in your regular scss file.// No need to create separate theme file!// src/app/comp-a/[email protected] 'src/theme.scss';
$primary: map-get($my-theme, primary);button { background-color: mat-color($primary);}

Og det er alt.

Let’s see how this works. First, theme related rules are put into the component SCSS file, so no extra component level theme file required. Second, the main theme.scss does not need to know component level themes (since it does not need to import them), so a simple theme definition is adequate. Third, the component SCSS file is used with @Component so it is encapsulated correctly, which means we can simply define rules for button.

Predefined Theme Keys

Probably you have noticed the next problem. What are the foreground, primary in above theme files ( map-get($my-theme, primary))? Are there any other keys I can use?

Disse “nøgler” henviser til forskellige farver defineret i temaet. Jeg kunne dog ikke finde nogen dokumenter, der forklarede disse “nøgler”, så den eneste måde, jeg kunne finde ud af, er at læse kildekoden . (Selvom det siges, at gode programmører skal læse koden, er det bestemt ikke et godt tegn for et bibliotek at skulle læse koden.)

Åbn, node_modules/@angular/material/_theming.scssog du vil se definitionerne for disse nøgler. Til fremtidig reference vil jeg gerne sammenfatte nøglerne her.

$theme |- primary |- accent |- warn |- foreground | |- base | |- divider | |- dividers | |- disabled | |- disabled-button | |- disabled-text | |- hint-text | |- secondary-text | |- icon | |- icons | |- text | |- slider-min | |- slider-off | `- slider-off-active |- background | |- status-bar | |- app-bar | |- background | |- hover | |- card | |- dialog | |- disabled-button | |- raised-button | |- focused-button | |- selected-button | |- selected-disabled-button | |- disabled-button-toggle | |- unselected-chip | `- disabled-list-option `- is-dark // bool, whether dark theme or not

For eksempel, hvis du vil gengive en deaktiveret tekst i din komponent, kan du bruge følgende kode:

$foreground: map-get($my-theme, foreground);.disabled-text { color: mat-color($foreground, disabled-text);}

Okay, dette er nogle lektioner, jeg har lært af at kæmpe med kantet materiale. Håber dette indlæg er nyttigt, hvis du står over for lignende problemer.