angular實現皮膚主題切換的方案

分配了個給現有angular6項目實現主題切換的效果,實現light dark明暗兩種顯示效果,我使用scss css預處理器方便開發。
效果(只截了一點點):
圖片描述css

切換樣式 就是 實現css 的 變化,主要思路是經過在body 上控制自定義屬性的值實現樣式的控制,在body上 添加 data-theme-style=」dark」, 像這樣:html

<body data-theme-style="dark">
  <app-root></app-root>
</body>

咱們經過data-theme-style的值 來控制樣式,本項目中 值有 light,dark 分別表明明暗兩套主題app

首先把切換主題 須要變化的 樣式 抽離出來 定義成mixin,如:背景顏色,字體顏色,陰影,邊框等,,ide

這裏以背景顏色 和 字體顏色舉例:字體

@mixin mixin-bg-color($dark-color,$light-color){

  [data-theme-style="dark"] & {
    background-color: $dark-color;
  }
  [data-theme-style="light"] & {
    background-color: $light-color;
  }
}

@mixin mixin-font-color($dark-color,$light-color){

  [data-theme-style="dark"] & {
    color: $dark-color;
  }
  [data-theme-style="light"] & {
    color: $light-color;
  }
}

在須要使用相關樣式的選擇器裏應用mixin:ui

@include mixin-font-color(blue,red)

舉個使用的例子,在data-theme-style=dark時 讓 .title 類的字體顏色變爲藍色 在data-theme-style=light時 讓 .title 類的字體顏色變爲紅色:this

@mixin mixin-font-color($dark-color,$light-color){

  [data-theme-style="dark"] & {
    color: $dark-color;
  }
  [data-theme-style="light"] & {
    color: $light-color;
  }
}


.main{

  .title{
    @include mixin-font-color(blue,red)
  }

}

上方的scss 編譯成css後的結果:spa

[data-theme-style="dark"] .main .title {
  color: blue; }
[data-theme-style="light"] .main .title {
  color: red; }

這樣一看 就很明白了。
接下來就是實現切換到效果,我這裏是點擊一個按鈕 實現 dark 和light 的來回切換,
在html模板上:code

<button class="switch-theme-btn" (click)="changeTheme()">{{theme | uppercase}}</button>

ts 代碼以下,註釋很清楚了:component

/**
   * 使用localStorage 存儲主題的名稱
   * @param theme
   */
  saveTheme(theme): void {
    localStorage.setItem(`theme`, theme);
  }

  /**
   * 獲取主題名稱並設置到body
   */
    getTheme(): void {
      let theme = localStorage.getItem(`theme`); // 獲取主題名稱
      if (!theme) {
        theme = `dark`; // 本地存儲中沒有theme的話 使用dark主題
      }
      const body = document.getElementsByTagName('body')[0];
      body.setAttribute('data-theme-style', theme); // 設置data-theme-style 屬性
      this.theme = theme; // 用於界面顯示
    }
  /**
   * 點擊按鈕 觸發改變主題的方法
   */
  changeTheme(): void {
    const body = document.getElementsByTagName('body')[0];
    if (body.getAttribute(`data-theme-style`) === 'dark') {
      this.saveTheme(`light`); // 保存
      this.getTheme(); // 更新獲取
    } else {
      this.saveTheme(`dark`); // 保存
      this.getTheme(); // 更新獲取
    }
  }

在組件的 ngOnInit() 生命週期 調用下 this.getTheme() 初始化。。

作完這些 已經能夠實現主題的切換了 ,可是 上方的 樣式 寫在公共的樣式表裏纔有效,由於組件的樣式只對對應的組件生效,使用[data-theme-style=」dark」]屬性選擇器沒法匹配到對應的元素,該屬性是定義在body上的,組件上確定是沒有的。 如何在組件的樣式裏生效呢,這個問題困擾了我一陣子,仍是在官網文檔找到答案:

:host-context 選擇器
有時候,基於某些來自組件視圖外部的條件應用樣式是頗有用的。 例如,在文檔的 元素上可能有一個用於表示樣式主題 (theme) 的 CSS 類,你應當基於它來決定組件的樣式。
這時能夠使用 :host-context() 僞類選擇器。它也以相似 :host() 形式使用。它在當前組件宿主元素的祖先節點中查找 CSS 類, 直到文檔的根節點爲止。在與其它選擇器組合使用時,它很是有用。

參考:https://www.angular.cn/guide/...

根據文檔的說明,咱們把前面的mixin改一下:

@mixin mixin-font-color($dark-color,$light-color){

  :host-context([data-theme-style="dark"]) & {
    color: $dark-color;
  }
  :host-context([data-theme-style="light"]) & {
    color: $light-color;
  }
}


.main{

  .title{
    @include mixin-font-color(blue,red)
  }

}

生成 的css 是這樣的:

:host-context([data-theme-style="dark"]) .main .title {
  color: blue; }
:host-context([data-theme-style="light"]) .main .title {
  color: red; }

至此 大功告成

原文地址:https://www.crazyming.com/note/705/

相關文章
相關標籤/搜索