Динамическое изменение styles.scss в Angular
Я хочу применять динамически SCSS-стиль в соответствии с переменной, известной до начальной загрузки. Можно styles.scss
программным образом изменить styles.scss
? В main.ts
перед начальной main.ts
я хочу добавить динамически строку типа:
@import 'assets/styles/customerA/_themes.scss';
or
@import 'assets/styles/customerB/_themes.scss';
в зависимости от значения переменной, поступающего с сервера.
Если вышеуказанное не представляется возможным, есть ли способ заполнить styles.scss
содержимым другого файла, который будет определен на сервере? Я хочу изменить styles.scss
а не любой другой "локальный" scss файл.
Ответы
Ответ 1
После того, как я много боролся с этим, я нашел ответ в CSS variables
. Это именно то, что я искал! Вы можете изменить их во время выполнения, и поэтому динамическая тематика выполнима. Это очень хорошая статья, описывающая шаги в Angular:
https://medium.com/@amcdnl/theming-angular-with-css-variables-3c78a5b20b24
Ответ 2
Я бы порекомендовал вам следующую общую форму сайта Angular Material: https://github.com/angular/material.angular.io/blob/master/angular.json. Стоит клонировать это репо и играть с ним локально. Есть несколько движущихся частей.
В вашем файле angular.json вы добавите css следующим образом. Обратите внимание, что вам нужно будет скомпилировать ваш scss для css отдельно, чтобы это работало. Они делают это в скрипте 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"
},
Затем посмотрите на менеджера стиля: https://github.com/angular/material.angular.io/blob/master/src/app/shared/style-manager/style-manager.ts
Вы создадите функцию для динамического добавления и удаления этой таблицы стилей по мере необходимости:
function createLinkElementWithKey(key: string) {
const linkEl = document.createElement('link');
linkEl.setAttribute('rel', 'stylesheet');
linkEl.classList.add(getClassNameForKey(key));
document.head.appendChild(linkEl);
return linkEl;
}
Затем в ThemePicker вы создадите наблюдаемый, чтобы управлять настройкой и удалением темы. См. (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);
}
}
Лично я об этом поступил несколько иначе, но это означало, что scss компилируется в один файл css, и класс выбирается динамически. Их способ добавляет дополнительный шаг сборки, но позволяет скомпилировать scss для ленивой загрузки.
Управление глобальными стилями
Вы заметите в своем файле angular.json, что у них есть main.scss, который используется независимо от выбранного вторичного стиля. Этот файл будет обрабатывать любые глобальные темы, которые вам нужны. Обратите внимание, что в их main.scss они импортируют несколько партиций Sass partials
. Они позволяют устанавливать глобальные стили для любой темы. Вы можете исследовать, как они используются, основная причина, по которой они используют частичные, заключается в том, что они могут передавать переменные из вторичных sass файлов вплоть до этих частичных данных с помощью mixins.
@mixin material-docs-app-theme($theme) {
$primary: map-get($theme, primary);
.docs-primary-header {
background: mat-color($primary);
map-get
- это функция Sass, которая позволяет вам определять объект и использовать его значения в Mixins. Конструкция материалов имеет функцию sass, которую они используют здесь, но вы можете использовать более простой способ захватить собственный цвет в вашем main.scss. В вашем стиле-a/style-b scss создайте настраиваемую тему.
$my-custom-theme: (
background-color: #ffff,
button-background: rgba(200, 200, 200, 0.6),
foreground: #34383c
);
Затем вы измените свой @include на:
@include material-docs-app-theme($theme, $my-custom-theme);
Материал-docs-app-theme mixin изменится на:
@mixin material-docs-app-theme($theme, $my-custom-theme) {
$background-color: map-get($my-custom-theme, background-color);
.our-background {
background-color: $background-color;
}
Это позволяет вам определять пользовательские цвета в отдельных листах с ленивым загружением и иметь их в глобальном main.scss. Mixins и Partials от Sass делают это возможным.
Ответ 3
ngOnInit() {
// Do some stuff to figure out which css url you want
this.cssUrl = '/assets/styles1.css';
}
В вашем html файле
<link rel="stylesheet" [href]='sanitizer.bypassSecurityTrustResourceUrl(cssUrl)'>
Ответ 4
У меня есть 2 идеи, с которыми вы могли бы поиграть...
1) Угловые компоненты имеют стили, которые могут принимать файлы.scss. Однако, похоже, вы не можете легко заменить свойство stylesUrl. Однако вы можете легко заменить сам компонент...
В основном ваше фактическое приложение будет обернуто в приложение "shell", и только ответственность за то, чтобы он втянул правильный файл.scss. Более конкретно, это было бы обернуто в две разные оболочки, по одному для каждого стиля.
@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 {}
Тогда тривиально заменить 2 компонента.
2) Моей второй идеей было бы использовать The Angular Material Themes, их можно легко поменять как таковые:
@import '[email protected]/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);
}
Ответ 5
Просто идея, которая может работать. (происхождение)
Предполагается, что для изменения файла среды, но я предполагаю, что он должен работать и для стилей.
Вы можете изменить файл стилей с помощью fileReplacements
в angular.json, но это потребует, чтобы вы каждый раз перестраивали приложение.
В вашем файле angular.json:
проекты> public> architect> build> конфигурации
"customerA": {
"fileReplacements": [
{
"replace": "src/styles.scss",
"with": "assets/styles/customerA/_themes.scss"
}
]
},
"customerB": {
"fileReplacements": [
{
"replace": "src/styles.scss",
"with": "assets/styles/customerB/_themes.scss"
}
]
}
проекты> public> architect> serve> конфигурации
"customerA": {
"browserTarget": "public:build:customerA"
},
"customerB": {
"browserTarget": "public:build:customerB"
},
Теперь вы можете запустить ng serve -c customerA
или ng serve -c customerB
чтобы получить соответствующую таблицу стилей.
Когда вы будете готовы к производству, вы можете либо развернуть вручную дважды, либо попробовать эту идею для перевода углового приложения.
PS Если вам нужно изменить только несколько стилей, я могу предположить, что вы используете переменные css.