【问题标题】:access SASS values ($colors from variables.scss) in Typescript (Angular2 ionic2)在 Typescript (Angular2 ionic2) 中访问 SASS 值(来自 variables.scss 的 $colors)
【发布时间】:2017-08-15 08:28:34
【问题描述】:

在 Ionic 2 中,我想从“[我的项目]\src\theme\variables.scss”文件中访问$colors 变量。

此文件包含:

$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 '的东西。

有人有想法吗?

【问题讨论】:

  • 如果您使用 CSS 变量(自定义属性),您可以使用 getComputedStyle 轻松获取它们。
  • This 似乎是另一种解决方案。

标签: angular typescript sass ionic2


【解决方案1】:

不幸的是,没有办法直接从 typescript/javascript 代码访问 SASS 变量。但是,我们可以制定一种解决方法来访问这些变量。

让我简要描述一下从 typescript 源代码中访问 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 文件中,我们只需在 DOM 的 body 部分中创建自定义属性。您应该使用名为define-custom-propertymixin 将希望可访问的每个 SASS 变量添加到此 SCSS 文件中,该文件需要两个参数:变量名和变量值。

例如,我为$colors 中定义的所有颜色 添加了条目,并为我的主题/ 中定义的SASS 变量$background-color 添加了一个条目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 Helper 组件

从现在开始,我们可以按照标准的Ionic2框架原则进行组件的集成和使用。

  • 将组件类名称 (SassHelperComponent) 添加到 app.module.tsNgModule 的声明部分中强>
  • 将以下 HTML 代码插入您要访问这些魔术变量的页面的 HTML 模板中:

    &lt;sass-helper&gt;&lt;/sass-helper&gt;


3。使用辅助组件

在页面的 TS 文件中,您应该在页面类中插入以下行:

@ViewChild(SassHelperComponent)
private sassHelper: SassHelperComponent;

最后,你可以通过调用子类方法来读取任何 SASS 变量的值,如下所示:

// Read $background-color:
this.sassHelper.readProperty('background-color');

// Read primary:
this.sassHelper.readProperty('primary');

【讨论】:

  • 是的,但必须有更简单的方法。
  • 是的,我希望有一种更简单的方法,但请记住,SASS 必须编译为 CSS,因此,所有变量定义在编译后都会丢失。直接从 typescript 代码访问 SASS 文件是一种替代方法,但是,它需要解析和 HTTP 访问,这是另一个麻烦。
  • 还没来得及尝试(优先级转移),但由于它已经有两票赞成,它似乎得到了其他用户的验证。感谢您的帮助@Mete Cantimur。我知道我会在某个时候使用您的意见。
  • @Mete Cantimur ,我终于实现了它并且它有效。谢谢(在验证之上给予支持)。我所做的唯一稍微不同的想法是将 "sass-helper.component.ts" 和 "sass-helper.component.scss" 重命名为 "sass-helper.ts" 和 "sass-helper.scss" 。在此之前,在 Chrome 控制台中进行控制时,颜色不在 CSS 的 body 中。
  • 对于那些复制/粘贴并且它不保存到正文的操作 - 操作忘记在 @Component 声明中包含 styleUrls: ['./sass-helper.component.scss'] 。如果不包括在内,则 scss 永远不会运行,并且不会将内容添加到正文中 - 因此,在 javascript 中读取它们时会出现空白变量。
【解决方案2】:

一种可能性是从.scss 文件生成.ts 文件。此过程的一个简单示例:

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 文件中,并使其在每个操作系统上都能运行。

【讨论】:

【解决方案3】:

这可以通过 CSS 模块实现。

CSS 模块

来自项目description

从 JS 模块导入 CSS 模块时,它会导出一个具有从本地名称到全局名称的所有映射的对象。

我们可以像这样从 css/scss 文件中读取变量:

import styles from "./style.css";    

element.innerHTML = '<div class="' + styles.className + '">';

默认情况下,Angular CLI 已经设置了对 CSS 模块的支持,它使用配置了 css-loader 的 Webpack。

使其工作的步骤是:

  1. 仅导出您要使用的 scss 变量。
  2. styles.scss 配置一个打字稿模块。
  3. 在您的打字稿组件中导入变量。

1 - 导出变量

在您的styles.scss 中,使用关键字:export 导出$colors。看来:export不支持导出map,只支持字符串,所以我们必须创建一个mixin来将map转换成字符串:

$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 code 这样的编辑器中获得一些好处:

更新:

上述配置仅在 ng 10 之前有效。Css Modules 配置从 ng 10 到 ng 11 发生了很大变化。

【讨论】:

  • 指出导出必须在全局 scss 文件中进行可能会有所帮助,因为 Angular 仅使用 Webpack css-loader 来解析全局样式。
  • 我似乎无法让它工作。当我导入模块时,我得到的只是一个空对象 ({})。我的帖子内容完全相同。自此设置以来有什么变化吗?
  • @ReneHamburger 我也无法让它工作。从字面上逐行复制步骤。在我尝试import styles from '../../styles.scss'; 的组件中,它会导致错误"export 'default' (imported as 'styles') was not found in '../../styles.scss'
  • 您使用的是哪个 Angular 版本?
  • @tiagolisalves 11.0.5
【解决方案4】:

我想在@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 才能让它修改正文样式。

希望这会有所帮助。

【讨论】:

  • 对我不起作用。在body 中仍然没有样式。你也没有使用sassHelper ...
  • @testing 我将 sassHelper 重命名为 StylesHelperComponent。你可以给它起任何名字:)。尝试从 styles.scss 中保存一些自定义属性,看看它是否保存。您可以从 DevTools > Elements > Computer Styles 检查。如果它出现在那里,那么您的问题肯定与视图封装有关。
  • 我现在使用ng gc SassHelper,而不是创建单独的文件。导入样式表并包含您的提示后,它似乎可以工作。谢谢!
  • 整个组件样式辅助方法是否用于获取已在 DOM 中某处应用的样式?我希望能够读取在任何地方都不需要使用的 scss 变量……所以我猜这种方法行不通,对吗?
【解决方案5】:

我知道这个问题现在已经有几年了,但我想我会分享我使用的解决方案。这是@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');

【讨论】:

    【解决方案6】:

    在 Windows 中,我使用了以下来自 Bersling 的回答。

    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']);
    

    【讨论】:

      猜你喜欢
      • 2016-06-22
      • 2017-09-06
      • 2016-06-23
      • 2016-07-28
      • 2016-11-14
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多