navigationend - Cambie styles.scss dinĂ¡micamente en Angular
router events subscribe angular 4 (5)
Quiero aplicar dinámicamente el estilo SCSS de acuerdo con una variable, conocida antes del arranque angular. ¿Es posible cambiar styles.scss
programáticamente? En main.ts
antes de bootstrapping, quiero agregar dinámicamente una línea como:
@import ''assets/styles/customerA/_themes.scss'';
or
@import ''assets/styles/customerB/_themes.scss'';
Dependiendo del valor de una variable proveniente del servidor.
Si lo anterior no es factible, ¿hay alguna manera de llenar styles.scss
con el contenido de otro archivo que se definirá en el servidor? Quiero cambiar styles.scss
y no cualquier otro archivo scss "local".
Después de haber luchado mucho con él, encontré la respuesta en las CSS variables
. ¡Eso es exactamente lo que estaba buscando! Puede cambiarlos durante el tiempo de ejecución y, por lo tanto, la temática dinámica es factible. Este es un muy buen artículo que describe los pasos en Angular:
https://medium.com/@amcdnl/theming-angular-with-css-variables-3c78a5b20b24
Recomendaría seguir la forma general del sitio web de material angular: https://github.com/angular/material.angular.io/blob/master/angular.json . Vale la pena clonar este repositorio y jugarlo localmente. Hay varias partes móviles.
En su archivo angular.json agregará el css de la siguiente manera. Tenga en cuenta que necesitará compilar su scss a css por separado para que esto funcione. Lo hacen en el script tools/build-theme.sh
. :
{
"input": "src/assets/customer-1-theme.css",
"lazy": true,
"bundleName": "customer-1-theme"
},
{
"input": "src/assets/customer-2-theme.css",
"lazy": true,
"bundleName": "customer-2-theme"
},
Luego, mire su administrador de estilo: https://github.com/angular/material.angular.io/blob/master/src/app/shared/style-manager/style-manager.ts
Creará una función para agregar y eliminar dinámicamente esta hoja de estilo según sea necesario:
function createLinkElementWithKey(key: string) {
const linkEl = document.createElement(''link'');
linkEl.setAttribute(''rel'', ''stylesheet'');
linkEl.classList.add(getClassNameForKey(key));
document.head.appendChild(linkEl);
return linkEl;
}
Luego, en el Selector de temas, configurará un observable para administrar la configuración y eliminación del tema. Consulte ( https://github.com/angular/material.angular.io/blob/master/src/app/shared/theme-picker/theme-picker.ts ):
installTheme(themeName: string) {
const theme = this.themes.find(currentTheme => currentTheme.name === themeName);
if (!theme) {
return;
}
this.currentTheme = theme;
if (theme.isDefault) {
this.styleManager.removeStyle(''theme'');
} else {
this.styleManager.setStyle(''theme'', `assets/${theme.name}.css`);
}
if (this.currentTheme) {
this._themeStorage.storeTheme(this.currentTheme);
}
}
Personalmente, lo hice de una manera ligeramente diferente, pero eso significaba que el scss se compila en un archivo css, y la clase se selecciona dinámicamente. Su forma agrega un paso de compilación adicional, pero permite que los scss compilados se carguen perezosamente.
Gestionando estilos globales
Notarás en su archivo angular.json que tienen un main.scss que se usa independientemente del estilo secundario elegido. Este archivo manejará cualquier tema global que necesites. Note que en su main.scss importan varios Sass partials
. Esto les permite establecer estilos globales para cualquier tema. Puede investigar cómo se usan, la razón principal por la que usan parciales aquí es que pueden pasar variables desde los archivos de sass secundarios hasta estos parciales mediante el uso de mixins.
@mixin material-docs-app-theme($theme) {
$primary: map-get($theme, primary);
.docs-primary-header {
background: mat-color($primary);
map-get
es una función Sass, que te permite definir un objeto y usar sus valores en Mixins. El diseño de materiales tiene una función sass que están usando aquí, pero podría usar un método más sencillo para obtener un color personalizado en main.scss. En tu estilo-a / style-b scss crea un tema personalizado.
$my-custom-theme: (
background-color: #ffff,
button-background: rgba(200, 200, 200, 0.6),
foreground: #34383c
);
Luego, cambiarías su @include a:
@include material-docs-app-theme($theme, $my-custom-theme);
El material-docs-app-theme mixin cambiaría a:
@mixin material-docs-app-theme($theme, $my-custom-theme) {
$background-color: map-get($my-custom-theme, background-color);
.our-background {
background-color: $background-color;
}
Esto le permite la oportunidad de definir colores personalizados en las hojas de estilo individuales cargadas perezoso y tenerlas disponibles en un main.scss global. Los mixins y los parciales de Sass hacen esto posible.
Sólo una idea que podría funcionar. ( origin )
Se supone que debe ser para cambiar el archivo del entorno, pero supongo que debería funcionar también para los estilos.
Puede cambiar el archivo de estilos usando fileReplacements
en angular.json, pero esto requerirá que reconstruya la aplicación cada vez.
En tu archivo angular.json:
proyectos> público> arquitecto> construir> configuraciones
"customerA": {
"fileReplacements": [
{
"replace": "src/styles.scss",
"with": "assets/styles/customerA/_themes.scss"
}
]
},
"customerB": {
"fileReplacements": [
{
"replace": "src/styles.scss",
"with": "assets/styles/customerB/_themes.scss"
}
]
}
proyectos> público> arquitecto> servir> configuraciones
"customerA": {
"browserTarget": "public:build:customerA"
},
"customerB": {
"browserTarget": "public:build:customerB"
},
Ahora puede ejecutar ng serve -c customerA
o ng serve -c customerB
para obtener la hoja de estilo correspondiente.
Cuando esté listo para la producción, puede implementarlo manualmente dos veces o intentar seguir esta idea para traducir una aplicación angular .
PD: Si solo necesita cambiar unos pocos estilos, le sugiero que utilice las variables css .
Tengo 2 ideas con las que podrías jugar ...
1) Los componentes angulares tienen un stylesUrls que puede tomar archivos .scss. Sin embargo, no parece que pueda reemplazar fácilmente la propiedad stylesUrl. Sin embargo, puedes cambiar fácilmente el componente ...
Básicamente, su aplicación real se envolverá en una aplicación "shell" cuya única responsabilidad es extraer el archivo .scss correcto. Más específicamente, se envolvería en 2 carcasas diferentes, una para cada estilo.
@Component({
selector: ''style-one-page'',
templateUrl: ''./app.component.html'',
styleUrls: [''./app-style-one-page.scss'']
})
export class WrapperStyleOneComponent extends PageComponent {}
@Component({
selector: ''style-two-page'',
templateUrl: ''./app.component.html'',
styleUrls: [''./app-style-two-page.scss'']
})
export class WrapperStyleTwoComponent extends PageComponent {}
Entonces es trivial intercambiar los 2 componentes.
2) Mi segunda idea sería aprovechar los temas de material angular, que pueden intercambiarse fácilmente como tales:
@import ''~@angular/material/theming'';
@import ''themes-palettes'';
@import ''themes-common'';
@include mat-core();
@function custom-light-theme() {
@return (
primary: $primary-palette,
accent: $accent-palette,
warn: $warn-palette,
foreground: $foreground-palette,
background: $background-palette,
is-dark: false
);
}
$custom-light-theme: custom-light-theme();
@include angular-material-theme($custom-light-theme);
.dark-theme {
$mat-dark-theme: mat-dark-theme($dark-primary-palette, $dark-accent-palette, $dark-warn-palette);
@include angular-material-theme($mat-dark-theme);
}
ngOnInit() {
// Do some stuff to figure out which css url you want
this.cssUrl = ''/assets/styles1.css'';
}
En tu archivo html
<link rel="stylesheet" [href]=''sanitizer.bypassSecurityTrustResourceUrl(cssUrl)''>