Anglar 8とBootstrap 4に基づいて動的テーマ切り替えを実現する例示的なコード


効果
まず効果を見ます。

本論文では、Anglar 8とBootstrap 4に基づいて、上記のテーマ切替効果をどのように実現するかを紹介します。
デザイン
Bootstrapの設計に従って、boots watch.comから提供された無料テーマを使って上記の効果を実現します。Bootswatchは、フロントエンドプログラマに最大21種類の無料のBootstrapテーマを提供し、APIドキュメントインスタンスページを提供しています。HTML+jQueryの環境において、テーマの切り替えをどのように行うかを紹介します。実は、私達もBootstrap公式サイトで提供しているテーマ設計ツールを使って自分のテーマを設計することができます。これらのカスタマイズのテーマも本文で紹介した方法で使うことができます。関連のリソースアドレスを交換するだけでいいです。BootswatchのAPIを開くと、様々なテーマのメタデータ情報が見られます。ここでcssMinリンクを使って、ホームページのリンクを変えて、テーマを切り替える目的を達成します。
着工する前に、ラフなデザインをします。簡単のために、私はBootstrapのNavbarを使ってこの機能を完成します。Navbarのコードは直接Bootstrap公式サイトからコピーしてきますので、少し変えてもいいです。違っているのは、一つのコンポーネントにNavbarをカプセル化するという利点は、テーマを切り替える機能をパッケージ化してモジュール化したデザインを実現できるということです。このデザインは下図に示されています。

基本的な流れは以下の通りです。
  • theme.service.tsは、Boots watchから主題情報を取得するサービスを提供する
  • 主なアプリケーションapp.com mponent.tsは、theme.service.tsを呼び出して、テーマ情報を取得し、テーマ情報をnav-bar.com onent.tsコンポーネント
  • に結び付ける。
  • 初めて実行されるサイトでは、environment.tsに定義されているデフォルト値をデフォルトテーマとして使用します。テーマを切り替えるたびに、選択されたテーマをnav-bar.mponent.tsにバインドして、選択されたテーマをプルダウンメニューに表示するために、選択されたテーマ名をLocal Strageに保存します。
  • nav-bar.com mponent.tsコンポーネントはNavbar上のdropdownにすべてのテーマ名を列記し、選択したテーマを表示します。ユーザーがあるテーマ名をクリックすると、themeSelection Changedイベントをトリガします。ap.com mponent.tsはこのイベントを受信すると、ホームページのリンクを交換し、テーマ設定
  • を完成します。
    ステップ
    まず、Bootswatch APIから返されるデータ構造に基づいて、データモデルを定義する。
    
    export class ThemeDefinition {
     name: string;
     description: string;
     thumbnail: string;
     preview: string;
     css: string;
     cssMin: string;
     cssCdn: string;
     scss: string;
     scssVariables: string;
    }
     
    export class Themes {
     version: String;
     themes: ThemeDefinition[];
    }
    その後、theme.service.tsサービスを作成し、Boots watch APIを起動するために使用される:
    
    import { Injectable } from '@angular/core';
    import { HttpClient } from '@angular/common/http';
    import { Observable } from 'rxjs';
    import { Themes } from '../models/themes';
     
    @Injectable({
     providedIn: 'root'
    })
    export class ThemeService {
     
     constructor(private http: HttpClient) { }
     
     getThemes(): Observable<Themes> {
     return this.http.get<Themes>('https://bootswatch.com/api/4.json');
     }
    }
    次に、Navbarコンポーネントを作成し、キーコード部分はテーマの名前をdropdownに結び付け、選択されたテーマ名に基づいて現在表示されているテーマ名がactiveであるべきかどうかを決定します。もちろん、dropdownの各アイテムはユーザーのクリックイベントにも応答しなければなりません。
    
    <nav class="navbar navbar-expand-lg navbar-dark bg-dark">
     <a class="navbar-brand" href="#" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" ><i class="fab fa-acquisitions-incorporated"></i></a>
     <button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarSupportedContent"
     aria-controls="navbarSupportedContent" aria-expanded="false" aria-label="Toggle navigation">
     <span class="navbar-toggler-icon"></span>
     </button>
     <div class="collapse navbar-collapse" id="navbarSupportedContent">
     <ul class="navbar-nav mr-auto">
      <li class="nav-item active">
      <a class="nav-link" href="#" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" >Home <span class="sr-only">(current)</span></a>
      </li>
      <li class="nav-item">
      <a class="nav-link" href="#" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" >Link</a>
      </li>
      <li *ngIf="themes" class="nav-item dropdown">
      <a class="nav-link dropdown-toggle" href="#" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" id="navbarDropdown" role="button" data-toggle="dropdown"
       aria-haspopup="true" aria-expanded="false">
         
      </a>
      <div class="dropdown-menu" aria-labelledby="navbarDropdown">
       <a *ngFor="let theme of themes.themes"
       [className]="theme.name === selectedTheme ? 'dropdown-item active' : 'dropdown-item'" href="#" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" 
       (click)="onThemeItemSelected($event)">{{theme.name}}</a>
      </div>
      </li>
     </ul>
     </div>
    </nav>
    Navbarコンポーネントのコードは以下の通りです。
    
    import { Component, OnInit, Output, EventEmitter, Input } from '@angular/core';
    import { Themes } from 'src/app/models/themes';
    import { ThemeService } from 'src/app/services/theme.service';
    import { ThemeDefinition } from 'src/app/models/theme-definition';
     
    @Component({
     selector: 'app-nav-bar',
     templateUrl: './nav-bar.component.html',
     styleUrls: ['./nav-bar.component.css']
    })
    export class NavBarComponent implements OnInit {
     
     @Input() themes: Themes;
     @Input() selectedTheme:string;
     @Output() themeSelectionChanged : EventEmitter<ThemeDefinition> = new EventEmitter();
     
     constructor(private themeService: ThemeService) { }
     
     ngOnInit() {
     }
     
     onThemeItemSelected(event: any) {
     const selectedThemeName = event.target.text;
     const selectedTheme = this.themes.themes.find(t => t.name === selectedThemeName);
     this.themeSelectionChanged.emit(selectedTheme);
     }
    }
    OneThe meItem Selectedイベントハンドリング関数では、クリックされたdropdown itemの名前を読み、その名前に基づいて選択されたテーマを見つけ、イベントデータとしてthemeSelectedイベントを開始し、その後、ap.com mponent.tsでこのイベントを処理します。このイベントハンドラ関数では、イベントデータから件名情報を取得してから、テーマを適用するためにアプリを起動します。
    
    import { Component, OnInit } from '@angular/core';
    import { ThemeDefinition } from './models/theme-definition';
    import { Themes } from './models/themes';
    import { ThemeService } from './services/theme.service';
    import { environment } from 'src/environments/environment';
    import { StorageMap } from '@ngx-pwa/local-storage';
     
    @Component({
     selector: 'app-root',
     templateUrl: './app.component.html',
     styleUrls: ['./app.component.css']
    })
    export class AppComponent implements OnInit {
     title = 'nblogger';
     themes: Themes;
     selectedTheme: string;
     
     constructor(private themeService: ThemeService,
     private storage: StorageMap) {
     
     }
     
     ngOnInit() {
     this.themeService.getThemes()
     .subscribe(data => {
      this.themes = data;
      this.storage.get('app-theme-name').subscribe(name => {
      const themeName = name ? name : environment.defaultTheme;
      const currentTheme = this.themes.themes.find(t => t.name === themeName);
      this.applyTheme(currentTheme);
      });
      
     });
     }
     
     onThemeSelectionChanged(event: ThemeDefinition) {
     this.applyTheme(event);
     }
     
     private applyTheme(def: ThemeDefinition): void {
     this.storage.set('app-theme-name', def.name).subscribe(()=>{});
     this.selectedTheme = def.name;
     const links = document.getElementsByTagName('link');
     for(let i = 0; i < links.length; i++) {
      const link = links[i];
      if (link.getAttribute('rel').indexOf('style') !== -1 &&
      link.getAttribute('type').indexOf('text') !== -1) {
       link.setAttribute('href', def.cssMin);
      }
     }
     }
    }
    appyThemeメソッドでは、まず選択したテーマ名をLocal Strageに設定し、次のページを開く時に直接テーマを適用することができます。そして、現在のdocumentから必要なlinkを見つけ、選択された主題情報のcssMinリンクアドレスにhref値を置き換える(内容はBoots watchのAPI結果を参照することができる)。
    ページを再开すると、app.com mponent.tsのngOnInit初期化方法が最初に呼び出され、theme.service.tsを通じてテーマ情報を読み取り、Locastrageに既に設定されているテーマがあるかどうかを判断します。ある場合は、このテーマを使用します。そうでない場合は、environment.tsのデフォルト値から件名を選択して設定します。
    app.com mponent.tsで使われているtemplateは比較的簡単で、本体はNavbarコンポーネントの引用であり、さらにいくつかの追加のHTML要素を加えて効果テストを行うことができます。
    
    <app-nav-bar [themes]="themes" [selectedTheme]="selectedTheme" (themeSelectionChanged)="onThemeSelectionChanged($event)"></app-nav-bar>
    <div class="container">
     <article>
     <h1>Heading 1</h1>
     <h2>Heading 2</h2>
     <h3>Heading 3</h3>
     <h4>Heading 4</h4>
     </article>
     <div class="alert alert-primary" role="alert">
            
     </div>
     <div class="alert alert-secondary" role="alert">
     A simple secondary alert―check it out!
     </div>
     <div class="alert alert-success" role="alert">
     A simple success alert―check it out!
     </div>
     <div class="alert alert-danger" role="alert">
     A simple danger alert―check it out!
     </div>
     <div class="alert alert-warning" role="alert">
     A simple warning alert―check it out!
     </div>
     <div class="alert alert-info" role="alert">
     A simple info alert―check it out!
     </div>
     <div class="alert alert-light" role="alert">
     A simple light alert―check it out!
     </div>
     <div class="alert alert-dark" role="alert">
     A simple dark alert―check it out!
     </div>
     
     <button type="button" class="btn btn-primary">Primary</button>
     <button type="button" class="btn btn-secondary">Secondary</button>
     <button type="button" class="btn btn-success">  </button>
     <button type="button" class="btn btn-danger">  </button>
     <button type="button" class="btn btn-warning">  </button>
     <button type="button" class="btn btn-info">  </button>
     <button type="button" class="btn btn-light">Light</button>
     <button type="button" class="btn btn-dark">Dark</button>
     
     <button type="button" class="btn btn-link">Link</button>
    </div>
    もちろん、index.htmlにlinkのプレースホルダを入れて、上記のappyTheme方法で見つけられます。
    
    <!doctype html>
    <html lang="en">
    <head>
     <meta charset="utf-8">
     <title>Nblogger</title>
     <base href="/" rel="external nofollow" >
     <meta name="viewport" content="width=device-width, initial-scale=1">
     <link rel="icon" type="image/x-icon" href="favicon.ico" rel="external nofollow" >
     <link rel="stylesheet" type="text/css" href="#" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" >
    </head>
    <body>
     <app-root></app-root>
    </body>
    </html>
    締め括りをつける
    Bootswatchのすべてのテーマを地元にダウンロードして、ローカルサービスによってテーマのAPIを提供します。このようにテーマの切り替えが速くなり、自分でテーマをカスタマイズして、この自作のローカルAPIを拡張して、より豊富なテーマを提供します。必要に応じて決めます。
    以上が本文の全部です。皆さんの勉強に役に立つように、私たちを応援してください。