Vue3,结合 sass 、Pinia 做主题切换

1,205 阅读2分钟

切换主题通常是日常模式和暗夜模式,通过页面按钮点击使页面呈色调为白色或黑色。

当前使用 sass ,配合 Pinia 去做到简易的切换主题功能。

sass

使用 sass 去配置页面主题对应的 css 样式

新建 theme.scss、handle.scss 文件

  • theme.scss 主要是设置主题颜色和制定对应样式
  • handle.scss 去设置使用切换对应样式的方法

themes.scss

其中 light 为日常主题,为白色调; dark 为暗夜主题,为黑色调。在里面设置背景颜色、字体颜色等样式。

// theme.scss
$themes: (
light: (
background_color: #fff,//背景色
text-color: rgba(0, 0, 0, 0.65), // 主文本色
),
dark: (
background_color: #121316,//背景
text-color: #fff, // 主文本色
)
);

handle.scss

定义好要在 vue 文件 style 中使用的方法

// handle.scss
@import "./themes.scss";
//遍历主题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);
}

//获取background-color背景颜色
@mixin background_color($color) {
  @include themeify {
    background-color: themed($color)!important;
  }
}

//获取字体颜色
@mixin font_color($color) {
  @include themeify {
    color: themed($color)!important;
  }
}

vite.config.ts

在 vite.config.ts 配置使用 上面的 handle.scss 文件,做到项目全局使用文件中 scss 的方法。

css: {
    preprocessorOptions: {
            scss: {
                additionalData: '@import "@/assets/styles/constant.scss";@import "@/assets/styles/handle.scss";'
            }
        }
    }

使用 sass 样式

在 style 中使用 @include 调用 handle.scss 中用 @mixin 定义好的方法。 其中 @minxin 方法传的值为 themes.scss 中定义对应样式的属性名

<style>
.box {
    @include background_color("background_color");
    @include background_color("font_color");
}
</style>

Pinia

Pinia 是 Vue 的专属状态管理库,它允许你跨组件或页面共享状态。

在页面组件中设置一个按钮,利用 Pinia 的状态管理,绑定方法做到全局切换样式

setting.ts

配置公共状态管理文件

利用 window.document.documentElement.setAttribute('data-theme', 'dark') 设置 html 的 attribute 属性

import { defineStore } from "pinia";
import { ref, computed } from "vue";

export const useSettingStore = defineStore(  
  "setting",
  () => {
    let title = ref<string>("不知名网站");
    let theme = ref<string>("dark");

    const titleDescribe = computed(() => `${title.value}是该网页的主题名`);

    // 主要部分================================
    function changeSettingTheme(e: string) {
      theme.value = e;
      window.document.documentElement.setAttribute("data-theme", e);
    }
    // =======================================

    function setTitle(e: string) {
      title.value = e;
    }

    return { title, theme, titleDescribe, changeSettingTheme, setTitle };
  },
  // 做持久化存储
  {
    persist: {
      enabled: true,
      // localStorage
      strategies: [{ key: 'theme', storage: sessionStorage, paths: ["theme"] }],
    },
  }
);

其中如果刷新页面的话,状态就会恢复初始状态。这个时候需要使用到 数据持久化存储 去保持主题的变化。

调用

<script setup lang="ts">
import { reactive, ref, onMounted } from "vue";
import { useSettingStore } from "@/stores/setting";

const settingStore = useSettingStore();
let inputChecked = ref<boolean>(false);

// 主要部分 ================
const changeTheme = () => {
  inputChecked.value = !inputChecked.value;
  let theme = inputChecked.value ? "dark" : "light";
  settingStore.changeSettingTheme(theme);
};
// ========================

onMounted(() => {
  inputChecked.value = settingStore.theme !== "dark";
  changeTheme();
});
</script>