Vue+Sass實現動態換膚

言明,本文實現的動態換膚並非elementUi官網那種隨意用ColorPicker實時更改主題的效果,而是爲系統預設的幾種主題事先配置顏色,然後線上觸發更改主題的事件。

首先感謝luanxiyuan老師的博文引導。

此方案涉及Sass的map遍歷、函數定義、map存取、混合器等相關知識,具體API詳參官網https://www.sass.hk/docs/。

大概的思路就是給html根標籤設置一個data-theme屬性,通過js切換data-theme的屬性值,sass根據此屬性來判斷使用對應主題變量。

具體實現步驟,以我的V5系統(dark、light)兩種主題爲例。

1.定義一個sass文件_themes.scss,存放系統中兩種主題的相關顏色變量,文件位置可以放在style或者assets目錄下,代碼如下

//定義全局主題&顏色的map數組,鑑於V5只有白天和晚上的主題,此處僅定義這兩種
//切記 所有顏色一式兩份兒,務必保證key值統一,key值可以自定義,注意避免$%_之類的,
//與sass自有符號衝突,見文知意即可
//另外如果基於其他UI框架,如本項目基於element-ui,則只需設置一套dark主題,
//data-theme爲dark時,樣式引用dark
//data-theme爲其他值時,自然就採用了elementui的默認樣式
$themes: (
  light: (
    font_color1: rgb(196, 193, 193),
    font_color2: rgb(110, 109, 109),
    background_color1: rgb(255, 0, 21),
    background_color2: rgb(87, 87, 226),
    border_color1: rgb(231, 181, 181),
    border_color2: rgb(9, 255, 0)
  ),
  dark: (
    font_color1: rgb(226, 222, 222),
    font_color2: rgb(255, 255, 255),
    background_color1: rgb(87, 87, 226),
    background_color2: rgb(255, 0, 21),
    border_color1: rgb(9, 255, 0),
    border_color2: rgb(231, 181, 181)
  )
);

這裏定義了一個map--$themes,分別存放對應主題的顏色變量集合。

注意,scss文件名建議用下劃線開頭,如_themes.scss,防止執行時被編譯成單獨的css文件,詳參sass中文教程(3.1 sass文件導入)。

2.定義另外一個sass文件_handle.scss來操作1中的$theme變量(當然兩個文件可以合併,分開寫是想把配置和操作解耦),上代碼:

@import "@/style/_themes.scss";
//此處用了sass的map遍歷、函數、map存取、混合器等相關知識,
//詳細API參考https://www.sass.hk/docs/

//遍歷主題map
@mixin themeify {
  @each $theme-name, $theme-map in $themes {
    //!global 把局部變量強升爲全局變量
    $theme-map: $theme-map !global;
    //這步是判斷html的data-theme的屬性值  #{}是sass的插值表達式
    //& sass嵌套裏的父容器標識   @content是混合器插槽,像vue的slot
    [data-theme="#{$theme-name}"] & {
      @content;
    }
  }
}
//聲明一個根據Key獲取顏色的function
@function themed($key) {
  @return map-get($theme-map, $key);
}

//暫時想到的常用的開發場景下面三種背景顏色、字體顏色、邊框顏色  至於陰影什麼之類的忽略了
//獲取背景顏色
@mixin background_color($color) {
  @include themeify {
    background-color: themed($color);
  }
}
//獲取字體顏色
@mixin font_color($color) {
  @include themeify {
    color: themed($color);
  }
}
//獲取邊框顏色
@mixin border_color($color) {
  @include themeify {
    border-color: themed($color);
  }
}

可以根據自己的使用場景自定義混入器,上面只定義了三個常用的,更改主題無非是更改背景&邊框&字體等的顏色。

3.具體在vue中使用,直接引入對應混入器就好,取哪個顏色,傳哪個key,就這麼簡單

<style lang="scss" scoped>
@import "@/style/_handle.scss";

p {
  font-size: 18px;
  @include font_color("font_color1");
  @include background_color("background_color1");
  @include border_color("border_color1");
}
</style>

到此,完畢了。至於怎麼動態切換html的屬性data-theme的值,那就駕輕就熟,js怎麼幹都行了,下面舉例一種:

<template>
  <div>
    <p>這裏是頁面</p>
    <button @click="toggleTheme(1)">白天</button>
    <button @click="toggleTheme(0)">晚上</button>
  </div>
</template>

<script>
export default {
  name: "HelloWorld",
  methods: {
    toggleTheme(index) {
      window.document.documentElement.setAttribute(
        "data-theme",
        index ? "dark" : "light"
      );
    }
  }
};

徹底over,不要吐槽我配置的color,純屬舉例。其他有不到的地方還請大神留言指正,非常感謝!

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章