【问题标题】:Angular 4 CLI, WebPack, switching bootstrap theme dynamically for the entire websiteAngular 4 CLI,WebPack,为整个网站动态切换引导主题
【发布时间】:2017-11-26 02:23:44
【问题描述】:

我想为用户提供一个按钮来改变整个网站的主题。我对所有内容都使用引导程序“.scss”文件。 这是我所做的:

我在“src/styles”文件夹中有“dark-styles.scss”和“light-styles.scss”。这两个文件都覆盖了我需要覆盖的类和方法,并且还从“node-module”导入了“bootstrap.scss”作为默认值。当我通过“.angular-cli.json”向应用程序提供任何这些文件时,如下所示;它完美地工作。

"styles": [
        "../node_modules/font-awesome/css/font-awesome.css",
        "../node_modules/@swimlane/ngx-datatable/release/index.css",
        "../node_modules/@swimlane/ngx-datatable/release/assets/icons.css",
        "../src/styles/dark-styles.scss"
      ],

或者,

"styles": [
        "../node_modules/font-awesome/css/font-awesome.css",
        "../node_modules/@swimlane/ngx-datatable/release/index.css",
        "../node_modules/@swimlane/ngx-datatable/release/assets/icons.css",
        "../src/styles/light-styles.scss"
      ],

如果我提供黑暗,主题就是黑暗,如果我提供光明,主题就是光明。

但我想要实现的是动态地允许用户更改主题。因此,基于stackoverflow中的其他答案;我访问了我的应用程序组件中的“文档”,这也是我的根组件。它使我可以访问整个 html 页面,其中我有一个可以从 app-component 设置的链接标签。

HTML 文件

<head>
<link id="theme" type="text/scss" rel="stylesheet" src="">
</head>
<body>
content .....
</body>

Angular-cli.json

"styles": [
        "../node_modules/font-awesome/css/font-awesome.css",
        "../node_modules/@swimlane/ngx-datatable/release/index.css",
        "../node_modules/@swimlane/ngx-datatable/release/assets/icons.css"
      ],

应用组件:

import { Component, OnInit, Inject } from '@angular/core';
import { DOCUMENT } from '@angular/platform-browser';

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
      styleUrls: ['./app.component.scss'],
    })
    export class AppComponent implements OnInit {
      currentTheme: string;

      constructor( @Inject(DOCUMENT) private document) {
      }

      ngOnInit() {
        this.currentTheme = 'dark';
        this.document.getElementById('theme').href = '../styles/dark-styles.scss';
      }

      handelChangeTheme(event) {
        if (this.currentTheme === 'dark') {
        this.document.getElementById('theme').href = '../styles/light-styles.scss';
          this.currentTheme = 'light';
          console.log('light');
        } else {
        this.document.getElementById('theme').href = '../styles/dark-styles.scss';
          this.currentTheme = 'dark';
          console.log('dark');
        }
      }
    }

在触发事件“handleChangeTheme”时,html 文件中#theme 的 href 更改。但它不会更新或应用样式。我知道它与 WebPack 以及它编译 scss 文件的方式有关。有没有人遇到过类似的情况或知道这个问题的解决方案。谢谢

【问题讨论】:

  • 我猜你必须编译两个 scss 文件并让它们可供应用程序选择(即将它们打包到你的 webapp 中)
  • @ochi ...也尝试过...没有用。这样做时,将应用默认引导程序,覆盖全部被拒绝。
  • 你解决了吗?我被指派做同样的事情。任何帮助将不胜感激
  • 不,我暂时把它放在一边......在材料中实现这一点很容易
  • Webpack 使用处理器来转换 Sass -> CSS。假设路径和文件类型正确,这似乎与 Material doc 使用的技术相同(右上角的油漆桶,选择主题更新 href 为 link.style-manager-theme:material.angular.io

标签: twitter-bootstrap angular webpack sass angular-cli


【解决方案1】:

我刚刚在本地完成了您的示例,在我将其更改为 text/css 后,type="text/scss" 似乎有问题,它开始工作。我首先认为您需要重新创建元素,但问题似乎与类型有关

由于它的主题,我建议您使用这些文件的编译 css 版本,将它们放入 assets 文件夹中,angular-cli 会将它们复制到 servebuild

此外,当您在 Angular 中引用 scss 时,它会使用 webpack 编译为 css。

【讨论】:

  • 我开始悬赏这个问题,因为我遇到了同样的问题。我结束了使用另一种方法解决它,更准确地说,类似于:sitepoint.com/sass-theming-neverending-story
  • @MarcusVinicius - 对您的方法进行更详细的解释会有所帮助。您是否将 scss 预编译为 css(如 Volodymyr Bilyachat 所建议的那样) - 这是使用 angular-cli 本身发生的,还是您必须添加一些手动 node-sass 命令才能使 htis 工作......以及您是如何切换主题的(使用链接?正如 Virodh 最初提出的那样?)
  • @RafiAliKhan,我添加了一个答案,更详细地解释了我如何设法使动态主题工作。
【解决方案2】:

我通过使用以下方法设法让动态主题在 Angular 4 + Bootstrap 中工作:

使用地图定义主题颜色:

$themes: (
    alpha: (
        primary: #2b343e,
        info: #3589c7,
        top-color: #000000,
        top-font-color: #ffffff,
        ...
    ),
    beta: (
        primary: #d2a444,
        info: #d2a444,
        top-color: #ffffff,
        top-font-color: #000000,
        ...
    )
)

然后,创建以下 mixin 来为每个主题名称和给定属性输出颜色

@mixin theme($property, $key, $themes: $themes) {
  @each $theme, $colors in $themes {
    &.theme-#{$theme},
    .theme-#{$theme} & {
      #{$property}: map-get($colors, $key);
    }
  }
}

我使用 mixins 来控制单个属性:

@mixin color($arguments...) {
  @include themify('color', $arguments...);
}

@mixin background-color($arguments...) {
  @include themify('background-color', $arguments...);
}

对于每个“主题化”组件,我在声明属性时必须使用上面的 mixins

.page-top {
    @include background-color('top-color');
    @include color('top-font-color');    
    height: 66px;
    width: 100%;
    ...    
}

CSS 输出类似于:

.page-top {
    height: 66px;
    width: 100%;
    ...    
}

.page-top.theme-alpha,
.theme-alpha .page-top {
    background-color: #000000;
    color: #ffffff;
}

.page-top.theme-beta,
.theme-beta .page-top {
    background-color: #ffffff;
    color: #000000;
}

最后,要使主题可用,您必须在某些父组件中控制主题类:

<!-- class="theme-alpha" -->
<main themeChange>
    <page-top></page-top>
    <sidebar></sidebar>
    <page-bottom></page-bottom>
</main>

themeChange 指令可以这样写:

@Directive({
  selector: '[themeChange]'
})
export class ThemeChange implements OnInit {
    @HostBinding('class') classes: string;
    private _classes: string[] = [];

    ngOnInit() {        
        // grab the theme name from some config, variable or user input
        this.classesString = myConfig.theme;
    }
}

【讨论】:

    【解决方案3】:

    经过几个小时的尝试,我终于让 bootstrap 主题切换器 工作了。这是我的解决方案:

    1. 不要使用 bootswatch.scss,而是下载每个主题的编译版本,将它们放在同一个资产文件夹中并相应地重命名文件。

    1. 将此行添加到 index.html。选择默认主题:

      < link id="theme" type="text/css" rel="stylesheet" href="/assets/css/theme_slate_bootstrap.min.css">
      ...
      ...
      <body class="theme-slate">
      ...
      


    3.目前在app.component中设置了切换主题的快捷方式。所以这是 app.component.ts

        import { Component, OnInit, Renderer2, Inject } from '@angular/core';
        import { DOCUMENT } from '@angular/platform-browser';
    
        @Component({
        selector: 'apps',
        templateUrl: './app.component.html'
        })
        export class AppComponent implements OnInit, OnDestroy {
            private currentTheme: string = 'slate';
    
            constructor(private renderer: Renderer2, @Inject(DOCUMENT) private document) { }
    
            ngOnInit() {}
    
            theme(type) {
                this.renderer.removeClass(document.body, 'theme-'+this.currentTheme);
                this.currentTheme = type;
                this.renderer.addClass(document.body, 'theme-'+this.currentTheme);
                this.document.getElementById('theme').href = '/assets/css/theme_'+type+'_bootstrap.min.css';
            }
        }
    
    1. 主题切换按钮

      <div style="display:block; position: absolute; top:0; right:0; text-align:right; z-index:100000;">
          <button class="btn btn-primary btn-sm" (click)="theme('slate')">Slate</button>
          <button class="btn btn-secondary btn-sm" (click)="theme('yeti')">Yeti</button>
          <button class="btn btn-secondary btn-sm" (click)="theme('darkly')">Darkly</button>
      </div>
      
    2. 在 angular.json 中添加这个自定义文件

      "styles": [
          "src/assets/scss/custom.scss"
      ],
      
    3. custom.scss - 添加您的自定义代码以在此处工作

      $themes: (
          slate: (
              name: 'slate',
              primary: #3A3F44,
              secondary: #7A8288,
              ...
          ),
          yeti: (
              name: 'yeti',
              primary: #008cba,
              secondary: #eee,
              ...
          ),
          darkly: (
              name: 'darkly',
              primary: #008cba,
              secondary: #eee,
              ...
          ),
      );
      
      /*
      * Implementation of themes
      */
      @mixin themify($themes) {
          @each $theme, $map in $themes {
              .theme-#{$theme} & {
              $theme-map: () !global;
              @each $key, $submap in $map {
                  $value: map-get(map-get($themes, $theme), '#{$key}');
                  $theme-map: map-merge($theme-map, ($key: $value)) !global;
              }
              @content;
              $theme-map: null !global;
              }
          }
      }
      
      @function themed($key) {
          @return map-get($theme-map, $key);
      }
      
      
      * {
          @include themify($themes) {
              // custom theme to your needs. Add here
              @if themed('name') == 'slate' {
              }
      
      
              @if themed('name') == 'yeti' {
              }
      
      
              @if themed('name') == 'darkly' {
              }
      
      
              // Below will effect all themes
              .btn, .form-control, .dropdown, .dropdown-menu {
                  border-radius: 0;
              }
      
              // This is just example to code. When switching theme, primary button theme should changed. Below code is not required. 
              .btn-primary {
                  background-color: themed('primary');
                  border-color: themed('primary');
              }
      
          }
      }
      // ***********************************************************************
      
      @import "custom-additional-classes";
      

    希望这对寻求引导主题切换器解决方案的每个人都有帮助

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2021-04-26
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-02-27
      • 1970-01-01
      相关资源
      最近更新 更多