Получить доступ к значениям SASS ($colors от variables.scss) в Typescript (Angular2 ionic2)
В Ionic 2 я хотел бы получить доступ к $colors
переменные из файла "[мой проект]\src\theme\variables.scss".
Этот файл содержит:
$colors: (
primary: #387ef5,
secondary: #32db64,
danger: #f53d3d,
light: #f4f4f4,
dark: #222,
favorite: #69BB7B
);
В компоненте я рисую холст. Это выглядит так:
import {Component, Input, ViewChild, ElementRef} from '@angular/core';
@Component({
selector: 'my-graph',
})
@View({
template: `<canvas #myGraph class='myGraph'
[attr.width]='_size'
[attr.height]='_size'></canvas>`,
})
export class MyGraphDiagram {
private _size: number;
// get the element with the #myGraph on it
@ViewChild("myGraph") myGraph: ElementRef;
constructor(){
this._size = 150;
}
ngAfterViewInit() { // wait for the view to init before using the element
let context: CanvasRenderingContext2D = this.myGraph.nativeElement.getContext("2d");
// HERE THE COLOR IS DEFINED AND I D LIKE TO ACCESS variable.scss TO DO THAT
context.fillStyle = 'blue';
context.fillRect(10, 10, 150, 150);
}
}
Как видно, в какой-то момент в этом коде определяется цвет фигуры: context.fillStyle = 'blue'
Я хотел бы использовать вместо этого что-то вроде context.fillStyle = '[variables.scss OBJECT].$colors.primary '
,
У кого-нибудь есть идея?
7 ответов
К сожалению, нет никакого способа получить доступ к переменной SASS непосредственно из машинописного кода / кода JavaScript. Тем не менее, мы можем обойти эти переменные.
Позвольте мне кратко описать шаги для доступа к переменным SASS из исходного текста машинописи:
1. Создание вспомогательного компонента SASS
Создайте ../providers/sass-helper/sass-helper.component.scss:
$prefix: "--"; //Prefix string for custom CSS properties
//Merges a variable name with $prefix
@function custom-property-name($name) {
@return $prefix + $name;
}
// Defines a custom property
@mixin define-custom-property($name, $value) {
#{custom-property-name($name)}: $value;
}
body {
// Append pre-defined colors in $colors:
@each $name, $value in $colors {
@include define-custom-property($name, $value);
}
// Append SASS variables which are desired to be accesible:
@include define-custom-property('background-color', $background-color);
}
В этом файле SCSS мы просто создаем пользовательские свойства внутри раздела body DOM. Вы должны добавить каждую переменную SASS, которую хотите, чтобы она была доступна, в этот файл SCSS с помощью миксина под названием define-custom-property
который ожидает два параметра: имя переменной и значение переменной.
В качестве примера я добавил записи для всех цветов, определенных в $colors
а также запись для переменной SASS $background-color
определено в моем файле theme / variables.scss. Вы можете добавить столько переменных, сколько пожелаете.
Создайте ../providers/sass-helper/sass-helper.component.ts:
import { Component } from '@angular/core';
export const PREFIX = '--';
@Component({
selector: 'sass-helper',
template: '<div></div>'
})
export class SassHelperComponent {
constructor() {
}
// Read the custom property of body section with given name:
readProperty(name: string): string {
let bodyStyles = window.getComputedStyle(document.body);
return bodyStyles.getPropertyValue(PREFIX + name);
}
}
2. Интеграция вспомогательного компонента SASS
Отныне мы можем следовать стандартным принципам Ionic2 для интеграции и использования компонентов.
- Добавьте имя класса компонента (SassHelperComponent) в раздел объявлений вашего NgModule в app.module.ts
Вставьте следующий HTML-код в HTML-шаблон вашей страницы, откуда вы хотите получить доступ к этим магическим переменным:
<sass-helper></sass-helper>
3. Использование вспомогательного компонента
В файле TS вашей страницы вы должны вставить следующие строки в ваш класс страницы:
@ViewChild(SassHelperComponent)
private sassHelper: SassHelperComponent;
Наконец, вы можете прочитать значение любой переменной SASS, просто вызвав метод дочернего класса следующим образом:
// Read $background-color:
this.sassHelper.readProperty('background-color');
// Read primary:
this.sassHelper.readProperty('primary');
Одна из возможностей заключается в создании .ts
файл из .scss
файл. Простой пример этого процесса:
1) Установить npm i --save-dev scss-to-json
,
2) Поместите это в свой package.json
:
"scripts": {
...
"scss2json": "echo \"export const SCSS_VARS = \" > src/app/scss-variables.generated.ts && scss-to-json src/variables.scss >> src/app/scss-variables.generated.ts"
},
и запустить его с npm run scss2json
, Пользователи Windows должны будут настроить пример.
3) Доступ к переменным:
import {SCSS_VARS} from './scss-variables.generated';
...
console.log(SCSS_VARS['$color-primary-1']);
Одним из преимуществ этого является то, что вы получите завершение типа от IDE, и это довольно простое средство для достижения вашей цели в целом.
Конечно, вы можете сделать это более продвинутым, например, создав сгенерированный файл только для чтения и поместив скрипт в его собственный .js
файл и заставить его работать на каждой ОС.
Это возможно с использованием модулей CSS.
Модули CSS
Из описания проекта:
При импорте модуля CSS из модуля JS он экспортирует объект со всеми сопоставлениями от локальных имен до глобальных имен.
Таким образом, мы могли читать переменные из файла css/scss следующим образом:
import styles from "./style.css";
element.innerHTML = '<div class="' + styles.className + '">';
Поддержка модулей CSS уже настроена по умолчанию в Angular CLI, который использует Webpack, настроенный с помощью css-loader.
Шаги, чтобы заставить его работать:
- Экспортируйте только те переменные scss, которые вы хотите использовать.
- Настройте модуль машинописного текста для
styles.scss
. - Импортируйте переменные в компоненты машинописного текста.
1 - Экспорт переменных
В твоем styles.scss
, используйте ключевое слово :export
для экспорта $colors. Кажется, что:export
не поддерживает экспорт карт, только строки, поэтому нам нужно создать миксин для преобразования карты в строки:
$colors: (
primary: #387ef5,
secondary: #32db64,
danger: #f53d3d,
light: #f4f4f4,
dark: #222,
favorite: #69bb7b,
);
@mixin rule($key, $value, $prefix) {
#{$prefix}-#{$key}: $value;
}
@mixin map-to-string($map, $prefix) {
@each $key, $value in $map {
@include rule($key, $value, $prefix);
}
}
:export {
@include map-to-string($colors, "colors");
}
Созданный :export
будет:
:export {
"colors-danger": "#f53d3d";
"colors-dark": "#222";
"colors-favorite": "#69bb7b";
"colors-light": "#f4f4f4";
"colors-primary": "#387ef5";
"colors-secondary": "#32db64";
}
2 - Настройте модуль машинописного текста для styles.scss
Мы должны создать styles.scss.d.ts
файл со следующим содержимым, чтобы разрешить импорт styles.scss
в наших файлах машинописного текста:
export interface globalScss {}
export const styles: globalScss;
export default styles;
3 - Импортируйте переменные в целевой машинописный компонент
Поскольку мы использовали экспорт по умолчанию, мы могли импортировать его в наш компонент следующим образом:
//...
import styles from 'src/styles.scss';
@Component({
selector: 'app-colors-use',
templateUrl: './colors-user.component.html',
styleUrls: ['./colors-user.component.scss'],
})
export class ColorsUserComponent implements OnInit {
buttonColor = styles["colors-primary"] //"#387ef5"
4 - (Плюс) Добавить определение типа в styles.scss.d.ts
Вы можете добавить информацию о типе в style.scss.d.ts
:
export interface globalScss {
"colors-danger": string
"colors-dark": string
"colors-favorite": string
"colors-light": string
/**
* Used for app-button, usually blue
*/
"colors-primary": string
/**
* Used for borders, usually green
*/
"colors-secondary": string
}
export const styles: globalScss;
export default styles;
Таким образом, у вас могут быть некоторые преимущества в редакторе, таком как код VS:
Я хотел бы добавить кое-что к ответу @ mete-cantimur.
import {Component, OnInit, ViewEncapsulation} from '@angular/core';
const PREFIX = '--';
@Component({
selector: 'app-styles-helper',
templateUrl: './styles-helper.component.html',
styleUrls: ['./styles-helper.component.scss'],
encapsulation: ViewEncapsulation.None
})
export class StylesHelperComponent implements OnInit {
ngOnInit(): void {
}
readProperty(name: string): string {
const bodyStyles = window.getComputedStyle(document.body);
return bodyStyles.getPropertyValue(PREFIX + name);
}
}
Мой вспомогательный компонент не мог изменять стили тела. Даже я все настроил правильно, пользовательские свойства не сохранялись.
Я должен был добавить encapsulation: ViewEncapsulation.None
к компоненту, чтобы позволить ему изменять стили тела.
Надеюсь это поможет.
Я знаю, что этому вопросу уже несколько лет, но я подумал, что поделюсь решением, которое использую. Это более упрощенная версия ответа @mete-cantimur, нет необходимости настраивать какие-либо дополнительные таблицы стилей CSS. Вместо этого он будет читать из загруженных стилей на странице.
import {Directive, ElementRef} from '@angular/core';
@Directive({
selector: '[css-helper]',
})
export class CssHelperDirective {
element: any;
constructor(_ref: ElementRef) {
this.element = _ref.nativeElement;
}
readProperty(name: string): string {
return window.getComputedStyle(this.element).getPropertyValue(name);
}
}
Применение:
<div #primary css-helper class="primary"></div>
@ViewChild('primary', {read: CssHelperDirective})
private cssHelper: CssHelperDirective;
let color = this.cssHelper.readProperty('background-color');
Еще один способ совместного использования переменных между файлами SASS и Typescript.
Сначала объявите переменные.
// Screen Sizes
$screen-tablet1: 768px;
$screen-tablet2: 800px;
$screen-tablet3: 1240px;
вstyles.scss
, прочитайте переменные и объявите пользовательские свойства CSS для глобального использования.
// import the declared variables
:root {
--screen-tablet1: #{$screen-tablet1};
--screen-tablet2: #{$screen-tablet2};
--screen-tablet3: #{$screen-tablet3};
}
Например, я хочу обновить количество столбцов сетки в зависимости от ширины экрана.
getGridCols(width: number) {
const sizeTablet1 = parseInt(
window
.getComputedStyle(document.documentElement)
.getPropertyValue('--screen-tablet1')
.replace('px', '')
);
const sizeTablet3 = parseInt(
window
.getComputedStyle(document.documentElement)
.getPropertyValue('--screen-tablet3')
.replace('px', '')
);
if (width < sizeTablet1) {
return 1;
}
if (width < sizeTablet3) {
return 2;
}
return 3;
}
В Windows я использовал следующее, взятое из ответа Берслинга.
npm i --save-dev ruoqianfengshao/scss-to-json
npm i --save-dev node-sass
"scripts": {
...
"scss2json": "echo export const SCSS_VARS = > .\\src\\app\\scss-variables.generated.ts && scss-to-json .\\src\\app\\_variables.scss >> .\\src\\app\\scss-variables.generated.ts"
}
npm run scss2json
import {SCSS_VARS} from './scss-variables.generated';
...
console.log(SCSS_VARS['$color-primary-1']);