web-dev-qa-db-ja.com

Angular 4 CLI、WebPack、切り替えbootstrap Webサイト全体のテーマを動的に

ウェブサイト全体のテーマを変更するボタンをユーザーに提供したい。私はすべてにbootstrap ".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の他の回答に基づいています。ルートコンポーネントでもあるアプリコンポーネントの「ドキュメント」にアクセスしました。 app-componentから設定できるリンクタグがあるHTMLページ全体にアクセスできます。

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の変更が変更されます。ただし、スタイルは更新または適用されません。私はそれがWebPackと関係していて、それがscssファイルをコンパイルする方法があることを理解しています。誰かが同様の状況に直面しているか、この問題の解決策を知っていますか?ありがとう

13
Virodh

私はあなたの例をローカルで実行しましたが、type="text/scss"に変更した後、text/cssで問題が発生するようです。最初に要素を再作成する必要があると思いましたが、問題はタイプにあるようです

そのテーマなので、これらのファイルのコンパイルされたcssバージョンを使用してそれらをassetsフォルダーに入れ、angular-cliがserveおよびbuildにコピーすることをお勧めします

また、angularでscssを参照すると、csへのwebpackでコンパイルされます。

6

数時間試した後、最終的にbootstrapテーマスイッチャーが機能するようになりました。これが私の解決策です:

  1. Bootswatch.scssを使用する代わりに、テーマごとにコンパイルされたバージョンをダウンロードし、同じアセットフォルダーに配置して、ファイルの名前を適宜変更します。

save compiled css

  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";
    

bootstrap themes switcherの解決策を探しているすべての人に役立つことを願っています

2
codetinker

次のアプローチを使用して、動的テーマを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 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;
    }
}
2
Marcus Vinicius