vue3 实现主题切换功能

主题切换是一个常见的功能,以下实现这个功能

1. 下载依赖

# 安装依赖
npm install sass element-plus

2.创建一个hooks用来管理主题 src/shared/hooks/theme.ts

import { ref } from "vue";

type ThemeType = "light" | "dark" | "red" | "system";

// 主题配置
const themeConfig = {
  light: {
    // --el-color-primary 修改的是element-plus主题色
    "--el-color-primary": "#409eff",
    "--bg-color": "#ffffff",
    "--text-color": "#303133",
  },
  dark: {
    // --el-color-primary 修改的是element-plus主题色
    "--el-color-primary": "#79bbff",
    "--bg-color": "#141414",
    "--text-color": "#e5eaf3",
  },
  red: {
    // --el-color-primary 修改的是element-plus主题色
    "--el-color-primary": "#fe6b00",
    "--bg-color": "#fe6b00",
    "--text-color": "#5a51f5",
  },
};

// 状态管理
const theme = ref<ThemeType>(
  (localStorage.getItem("theme") as ThemeType) || "light"
);

// 监听系统主题变化
const systemThemeMatch = window.matchMedia("(prefers-color-scheme: dark)");

// 获取当前生效主题
const getRealTheme = () => {
  if (theme.value === "system") {
    return systemThemeMatch.matches ? "dark" : "light";
  }
  return theme.value;
};

// 应用主题
const applyTheme = (themeType: "light" | "dark" | "red") => {
  const variables = themeConfig[themeType];
  Object.entries(variables).forEach(([key, value]) => {
    document.documentElement.style.setProperty(key, value);
  });
  document.documentElement.className = themeType;
};

// 初始化监听
const initThemeListener = () => {
  systemThemeMatch.addEventListener("change", () => {
    if (theme.value === "system") {
      applyTheme(getRealTheme());
    }
  });
};

// 切换主题
const toggleTheme = (newTheme: ThemeType) => {
  theme.value = newTheme;
  localStorage.setItem("theme", newTheme);
  applyTheme(getRealTheme());
};

export function useTheme() {
  return {
    theme,
    toggleTheme,
    initThemeListener,
    getRealTheme,
    applyTheme,
  };
}

3.main.ts 引入配置 

import { createApp } from "vue";
import App from "./App.vue";
import ElementPlus from "element-plus";
import "element-plus/dist/index.css";

import { useTheme } from "./utils/theme";

const app: any = createApp(App);

// 初始化主题
const { initThemeListener, applyTheme, getRealTheme } = useTheme();
app.use(ElementPlus, {
  theme: getRealTheme(),
});
applyTheme(getRealTheme());
initThemeListener();

app.mount("#app");

4.页面使用 

<template>
  <el-dropdown @command="handleCommand">
    切换主题
    <template #dropdown>
      <el-dropdown-menu>
        <el-dropdown-item command="light" :disabled="theme === 'light'">
          亮色模式
        </el-dropdown-item>
        <el-dropdown-item command="dark" :disabled="theme === 'dark'">
          暗黑模式
        </el-dropdown-item>
        <el-dropdown-item command="red" :disabled="theme === 'red'">
          红色模式
        </el-dropdown-item>
        <el-dropdown-item command="system" :disabled="theme === 'system'">
          跟随系统
        </el-dropdown-item>
      </el-dropdown-menu>
    </template>
  </el-dropdown>
  <div class="box">
    我是主题字体颜色
  </div>
  <el-button>我是一个按钮</el-button>
</template>

<script setup lang="ts">
import { useTheme } from '../utils/theme.ts'

const { theme, toggleTheme } = useTheme()

const handleCommand = (command: string) => {
  toggleTheme(command as ThemeType)
}
</script>
<style scoped lang="scss">
.box {
  width: 100px;
  height: 100px;
  background-color: var(--bg-color);
  color: var(--text-color);
}
</style>

### 动态主题切换功能实现Vue 3 和 TypeScript 中实现动态主题切换是一项常见的需求,可以通过组合 `Composition API`、`ref`、`watch` 等工具完成。以下是具体的实现方式: #### 主题管理逻辑 使用 `ref` 创建一个响应式的变量来存储当前的主题状态,并从浏览器的 `localStorage` 中读取已保存的主题配置。 ```typescript import { ref, watch } from &#39;vue&#39;; type ThemeType = &#39;light&#39; | &#39;dark&#39; | &#39;system&#39;; const theme = ref<ThemeType>( (localStorage.getItem(&#39;theme&#39;) as ThemeType) || &#39;light&#39; ); ``` 这段代码定义了一个名为 `theme` 的响应式变量[^1],其初始值来源于 `localStorage` 或者默认为 `&#39;light&#39;`。 #### 监听主题变化 利用 `watch` 方法监听 `theme` 的变化,在发生变化时同步更新 HTML 文档根节点的类名以及本地存储的状态。 ```typescript watch(theme, (newTheme) => { document.documentElement.setAttribute(&#39;data-theme&#39;, newTheme); if (newTheme === &#39;system&#39;) { const systemPreference = window.matchMedia(&#39;(prefers-color-scheme: dark)&#39;).matches ? &#39;dark&#39; : &#39;light&#39;; document.documentElement.classList.remove(&#39;light&#39;, &#39;dark&#39;); document.documentElement.classList.add(systemPreference); } localStorage.setItem(&#39;theme&#39;, newTheme); }); ``` 这里实现了当用户更改主题时自动调整页面样式的行为[^1]。如果选择了 `&#39;system&#39;` 模式,则依据用户的操作系统偏好设定相应的颜色方案。 #### 提供主题切换函数 为了方便外部调用,可以封装一个用于改变主题的方法——`setTheme`。 ```typescript function setTheme(newTheme: ThemeType): void { theme.value = newTheme; } ``` 该方法接收一个新的主题名称作为参数,并将其赋给 `theme` 变量,从而触发上面提到的变化侦测机制。 #### 组件交互部分 最后一步是在前端界面中加入控件让用户能够轻松地选择他们喜欢的颜色模式。通常这可以通过 `<select>` 下拉菜单或者按钮组的形式展现出来。 ```html <select @change="handleChange"> <option value="light">Light</option> <option value="dark">Dark</option> <option value="system">System</option> </select> ``` 配合之前定义好的 `setTheme` 函数编写事件处理器如下所示: ```typescript function handleChange(event: Event): void { const target = event.target as HTMLSelectElement; setTheme(target.value as ThemeType); } ``` 这样就完成了整个流程的设计与编码工作[^1]。 #### 解决可能遇到的问题 对于某些开发者来说,可能会面临 TypeScript 对于 `.vue` 文件支持不足的情况。这是因为普通的 TypeScript 编译器并不知道如何去解析单文件组件(SFC),所以需要额外安装插件或依赖项以便让编译过程顺利进行下去[^2]。 另外需要注意的是,有时候即使设置了正确的类型约束仍会出现警告提示比如 “no-inferrable-types”。对此可以在项目的 ESLint 配置文件里面添加特定规则忽略此类情况的发生[^3]: ```javascript rules: { &#39;@typescript-eslint/no-inferrable-types&#39;: &#39;off&#39;, }, ``` 以上就是关于如何基于 Vue 3 和 TypeScript 构建灵活可定制化的网站外观风格转换解决方案的一个简单介绍。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值