Получить доступ к значениям 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.

Шаги, чтобы заставить его работать:

  1. Экспортируйте только те переменные scss, которые вы хотите использовать.
  2. Настройте модуль машинописного текста для styles.scss.
  3. Импортируйте переменные в компоненты машинописного текста.

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']);
Другие вопросы по тегам