在Angular 2组件中访问Bootstrap的scss变量

24

我正在使用 Angular CLI 构建一个新的 Angular2 项目,并配置项目以使用 SCSS。我已经成功地将 Bootstrap 4 加载到我的 styles.scss 文件中,但是如果我尝试从组件内部访问 Bootstrap(或在 styles.scss 中定义的自己的变量),则会出现 Undefined Variable 的构建错误。

组件的样式文件是否在 angular-cli.json 中的 styles 节点的主入口之前编译?如何使全局级别定义的任何变量对应用程序中的所有组件都可用?谢谢!

angular-cli.json

"apps": [
  {
    ...
    "styles": [
      "styles/styles.scss"
    ],
    ...
  }
]

样式.scss

// Bootstrap
$enable-flex: true; // Enable Flexbox mode
@import "../../node_modules/bootstrap/scss/bootstrap";

组件

.navbar {
  background: $brand-primary; // Undefined variable here
}
3个回答

39

仅仅将Bootstrap 4导入到您的styles.scss中并不意味着您在组件的.scss文件中可以访问它。

在您的component.scss文件中,您需要导入Bootstrap变量:

@import '~bootstrap/scss/_variables.scss';

.navbar {
  background: $brand-primary; // No more Undefined variable here
}

解释

很多人似乎对此感到困惑,你不应该在组件中导入 bootstrap.scss ,而应该只导入你需要的内容。

如果你仔细查看 bootstrap.scss 的源代码,你会发现它们将每个部分都分开放在不同的文件中。你可以使用 mixins 文件夹和 _variables.scss 文件。这些应该是你在组件上导入的唯一文件,以避免 CSS 重复。

如果我在每个组件上都导入这些内容,会增加我的包大小吗?

不会增加。为什么呢?mixinsvariables 是 Sass 特有的(至少目前是这样),所以当你像这样将所有变量导入到组件中时:

@import '~bootstrap/scss/_variables.scss';

.navbar {
  background: $brand-primary;
}

那将会产生的输出CSS为:

.navbar {
  background: #007bff;
}

编译为 CSS 后,其余变量将被丢弃。


1
如果我有十二个组件,那么_variables.scss文件不会被读取十二次吗? - user663031
是的,它会被读取,但不会包含在代码中。请记住CSS没有变量。 - Fabio Antunes
1
~波浪符号是什么意思?这是在SCSS中引用[/*/**]/node_modules/{{packageName}}的方式吗?类似于TS中的@angular/core/... - Cody
是的,就是这样,除了 TS 部分,你不需要在从 node_modules 引用包时加上 @ 符号。在 TS 和 Node 中,任何绝对导入都会解析到 node_modules。 - Fabio Antunes
@FabioAntunes CSS有变量 :) - macwier

5
创建一个_colors.scss文件,将所有的颜色变量复制到其中,并在你的component.scss文件中引入该文件。

4
一些人建议在每个组件的.scss中导入variables.scss,但我觉得这样有点凌乱。这样做也无法很好地适应我们公司CSS的架构方式。我最终选择了这种方法,以便能够使用variables、mixins,并扩展样式。这还允许我在一个位置管理所有CSS。
我目前正在处理一个由Angular2 CLI生成的项目。所以有一个主要的style.scss。
另一种实现这一目标的方法是执行以下操作:
  1. Removing the styleUrls from the app.component.ts files.

    @Component({
        selector: 'app-root',
        templateUrl: './app.component.html'
        // styleUrls: ['./app.component.scss']
    });
    
  2. I manage all the less files in the main styles.scss. So my current setup looks something like:

    // Bootstrap
    @import "../node_modules/bootstrap-less/bootstrap/index";
    
    // Company Branding
    @import "theme/index";
    
    // Components
    @import "app/app.component.scss";
    @import "app/search/search.component.scss";
    

希望这个替代方案对某些人有所帮助。


这应该可以工作,但这种方式可能无法利用视图封装。我想你必须将你的组件更改为 encapsulation: ViewEncapsulation.None。我错了吗? - hgoebl
@hgoebl,那样做行不通。我使用封装的方式不同。在我们的编码风格中,我们总是有一个选择器来区分页面。我们不使用“封装”,而是使用该页面的特定选择器。 - Gene Parcellano
2
一个快速测试显示:重复导入似乎不会影响文件大小。我用了几个组件进行了检查,无论我是否在每个组件中都包含_variable.scss,有效文件大小都保持不变(尽管我没有检查文档甚至实现)。因此,@fabio-antunes的答案可能更好,因为它不会破坏封装性。 - Andreas Baumgart
但是,如果您将整个bootstrap.scss导入到每个组件的scss文件中,则主要的main.bundle.js文件会因为每个组件创建一堆与组件相关的定义而变得过于庞大。 - user6600768
@IgorBabic 为什么你在组件中导入整个 bootrap.scss,而你只需要变量或混合?你应该只导入你需要的内容。 - Fabio Antunes

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接