基于Angular 8和Bootstrap 4实现动态主题切换

栏目: IT技术 · 发布时间: 4年前

内容简介:(总访问量:17;当日访问量:1)

效果

首先看看效果:

基于Angular 8和Bootstrap 4实现动态主题切换

本文将介绍如何基于Angular 8和Bootstrap 4来实现上面的主题切换效果。

设计

遵循Bootstrap的设计,我们会使用 bootswatch.com 提供的免费主题来实现上面的效果。Bootswatch为前端 程序员 提供了多达21种免费的Bootstrap主题,并且提供了 API文档实例页面 ,介绍如何在HTML+jQuery的环境中实现主题切换。其实,我们也可以使用Bootstrap官网提供的主题设计 工具 来设计自己的主题,这些自定义的主题也是可以用在本文介绍的方法里的,只需要替换相关的资源地址就可以。如果你打开Bootswatch的API,你就会看到各种主题的元数据信息,我们可以使用其中的cssMin链接来替换主页的link地址,以达到切换主题的目的。

在开工之前,还是要做一些粗略的设计。为了简单起见,我使用Bootstrap的Navbar来完成这个功能,因为Navbar的代码可以直接从Bootstrap官网拷贝过来,稍微改改就行。不同的是,我将Navbar封装在一个组件(Component)里,这样做的好处是,可以将切换主题的功能封装起来,以实现模块化的设计。下图展示了这一设计:

基于Angular 8和Bootstrap 4实现动态主题切换

基本流程如下:

  • theme.service.ts提供从Bootswatch获取主题信息的服务
  • 主应用app.component.ts调用theme.service.ts,获取主题信息,并将主题信息绑定到nav-bar.component.ts组件
  • 第一次执行站点,站点会使用定义在environment.ts中的默认值作为默认主题,当每次切换主题时,会将所选主题绑定到nav-bar.component.ts上,用来在下拉菜单中标注已选主题,并将所选主题名称保存在LocalStorage,以便下次启动站点时直接应用已选主题
  • nav-bar.component.ts组件会在Navbar上的dropdown中列出所有的主题名称,并且标注所选主题,当用户点击某个主题名称时,就会触发themeSelectionChanged事件,app.component.ts接收到这个事件后,就会替换主页的link,完成主题设置

步骤

首先,根据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服务,用来调用Bootswatch 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的每个item还应该响应用户的点击事件:

<nav>
  <a href="#"><i></i></a>
  <button type="button" data-toggle="collapse" data-target="#navbarSupportedContent"
    aria-controls="navbarSupportedContent" aria-expanded="false" aria-label="Toggle navigation">
    <span></span>
  </button>
  <div id="navbarSupportedContent">
    <ul>
      <li>
        <a href="#">Home <span>(current)</span></a>
      </li>
      <li>
        <a href="#">Link</a>
      </li>
      <li *ngIf="themes">
        <a href="#" id="navbarDropdown" role="button" data-toggle="dropdown"
          aria-haspopup="true" aria-expanded="false">
          主题
        </a>
        <div aria-labelledby="navbarDropdown">
          <a *ngFor="let theme of themes.themes"
            [className]="theme.name === selectedTheme ? 'dropdown-item active' : 'dropdown-item'" href="#"
            (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);
  }
}

在onThemeItemSelected事件处理函数中,会读取被点击dropdown item的名称,根据该名称找到所选的主题,然后将其作为事件数据,发起themeSelectionChanged事件,然后,就是app.component.ts来处理这个事件了。在该事件处理函数中,从事件数据获取主题信息,然后调用applyTheme方法来应用主题:

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);
        }
    }
  }
}

在applyTheme方法中,首先会将所选主题名称设置到LocalStorage中,以便下次打开页面的时候能够直接应用主题;然后,从当前document中找到所需的link tag,并将其href值替换为所选主题信息的cssMin链接地址(内容可以参考Bootswatch的API结果)以此完成主题替换。

当重新打开页面时,app.component.ts中的ngOnInit初始化方法会被首先调用,它会通过theme.service.ts来读取主题信息,之后判断LocalStorage中是否有已经设置好的主题。如果有,则使用该主题,否则就从environment.ts的默认值中选择主题名称进行设置。

app.component.ts所使用的template就比较简单,主体是对Navbar组件的引用,还可以加一些额外的HTML元素进行效果测试:

<app-nav-bar [themes]="themes" [selectedTheme]="selectedTheme" (themeSelectionChanged)="onThemeSelectionChanged($event)"></app-nav-bar>
<div>
  <article>
  <h1>Heading 1</h1>
  <h2>Heading 2</h2>
  <h3>Heading 3</h3>
  <h4>Heading 4</h4>
  </article>
  <div role="alert">
    这是一个警告框
  </div>
  <div role="alert">
    A simple secondary alert—check it out!
  </div>
  <div role="alert">
    A simple success alert—check it out!
  </div>
  <div role="alert">
    A simple danger alert—check it out!
  </div>
  <div role="alert">
    A simple warning alert—check it out!
  </div>
  <div role="alert">
    A simple info alert—check it out!
  </div>
  <div role="alert">
    A simple light alert—check it out!
  </div>
  <div role="alert">
    A simple dark alert—check it out!
  </div>

  <button type="button">Primary</button>
  <button type="button">Secondary</button>
  <button type="button">成功</button>
  <button type="button">失败</button>
  <button type="button">警告</button>
  <button type="button">信息</button>
  <button type="button">Light</button>
  <button type="button">Dark</button>

  <button type="button">Link</button>
</div>

当然,记得在index.html中加入link的占位符,以便上面的applyTheme方法能够找到它:

<!doctype html>
<html lang="en">
<head>
  <meta charset="utf-8">
  <title>Nblogger</title>
  <base href="/">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <link rel="icon" type="image/x-icon" href="favicon.ico">
  <link rel="stylesheet" type="text/css" href="#">
</head>
<body>
  <app-root></app-root>
</body>
</html>

总结

我们可以将Bootswatch的所有主题下载到本地,由本地服务来提供主题的API,这样切换主题会变得更快,也可以自己自定义主题然后扩展这个自制的本地API来提供更丰富的主题,根据需要来定吧。

Happy coding…

基于Angular 8和Bootstrap 4实现动态主题切换

(总访问量:17;当日访问量:1)


以上所述就是小编给大家介绍的《基于Angular 8和Bootstrap 4实现动态主题切换》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

Learning PHP, MySQL, and JavaScript

Learning PHP, MySQL, and JavaScript

Robin Nixon / O'Reilly Media / 2009-7-21 / USD 39.99

Learn how to create responsive, data-driven websites with PHP, MySQL, and JavaScript - whether or not you know how to program. This simple, streamlined guide explains how the powerful combination of P......一起来看看 《Learning PHP, MySQL, and JavaScript》 这本书的介绍吧!

XML 在线格式化
XML 在线格式化

在线 XML 格式化压缩工具

Markdown 在线编辑器
Markdown 在线编辑器

Markdown 在线编辑器

RGB HSV 转换
RGB HSV 转换

RGB HSV 互转工具