主题切换的实现思路

322 阅读3分钟

学习主题切换功能

根据 Vant 源码学习 模仿实现主题切换功能

实现思路

  • 需要var() 变量控制
  • 存放 themelight 还是 dark
  • lightdark 分别有两种不同 颜色变量提供
  • 切换的时候 添加class 和 移除class

主要思路就是这么多 接下来 看一下var()变量需要哪些

vars.scss 文件:

这部分是之前搬了vant的变量来用,改了一下名字

:root {
    // colors
    --tsl-blck:#000;
    --tsl-white:#fff;
    --tsl-gray-1:#f7f8fa;
    --tsl-gray-2:#f2f3f5;
    --tsl-gray-3:#ebedf0;
    --tsl-gray-4:#dcdee0;
    --tsl-gray-5:#c8c9cc;
    --tsl-gray-6:#969799;
    --tsl-gray-7:#646566;
    --tsl-blue:#1989fa;
    --tsl-green:#33c88e;

    // sizes
    --tsl-padding: 24px;
    --tsl-row-max-width: 1680px;
    --tsl-nav-width: 220px;
    --tsl-border-radius: 20px;
    --tsl-simulator-width: 360px;
    --tsl-simulator-height: 620px;
    --tsl-header-top-height: 64px;
}


.tsl-theme-light {
    // text
    --tsl-text-color-1: var(--tsl-black);
    --tsl-text-color-2: var(--tsl-gray-8);
    --tsl-text-color-3: #34495e;
    --tsl-text-color-4: var(--tsl-gray-6);
    --tsl-link-color: var(--tsl-blue);

     // background
  --tsl-background: #eff2f5;
  --tsl-background-2: var(--tsl-white);
  --tsl-background-3: var(--tsl-white);
  --tsl-header-background: #011f3c;
  --tsl-border-color: var(--tsl-gray-2);

  // code
  --tsl-code-color: #58727e;
  --tsl-code-comment-color: var(--tsl-gray-6);
  --tsl-code-background: var(--tsl-gray-1);

  // blockquote
  --tsl-blockquote-color: #2f85da;
  --tsl-blockquote-background: #ecf9ff;
}


.tsl-theme-dark {
  // text
  --tsl-text-color-1: var(--tsl-white);
  --tsl-text-color-2: rgba(255, 255, 255, 0.9);
  --tsl-text-color-3: rgba(255, 255, 255, 0.75);
  --tsl-text-color-4: rgba(255, 255, 255, 0.6);
  --tsl-link-color: #1bb5fe;

  // background
  --tsl-background: #202124;
  --tsl-background-2: rgba(255, 255, 255, 0.06);
  --tsl-background-3: rgba(255, 255, 255, 0.1);
  --tsl-header-background: rgba(1, 31, 60, 0.3);
  --tsl-border-color: #3a3a3c;

  // code
  --tsl-code-color: rgba(200, 200, 200, 0.85);
  --tsl-code-comment-color: var(--tsl-gray-7);
  --tsl-code-background: rgba(0, 0, 0, 0.24);

  // blockquote
  --tsl-blockquote-color: #bae6fd;
  --tsl-blockquote-background: rgba(7, 89, 133, 0.25);
}

其实还是清晰可见,分成三个部分

  • :root
  • light
  • dark

其中 light 和 dark 两个类名 下面分别包含了不同的颜色值 都是基于root的色调,那么这就导致我切换到light 或者是dark 的时候,对应的颜色值也就发生了改变

注:没有使用过var()的话 可以去这里css var 函数

根据上面这句话很重要 接下来我们就需要写逻辑 来触发切换了,我使用的是 pnpm+vite+vue3+ts+scss 构建的一个简单项目

## 
pnpm create vite 手动选择 ts+vue
pnpm i 安装依赖包
pnpm i sass sass-loader -D 下载sass
pnpm dev 启动服务

把上面的变量存放在我们的style/vars.scss 的文件下 在引入到main.ts

剩余部分 我就统一放在App.vue 文件中了 下面就是我的结构

<template>
  <div class="wrapper">
    <ul class="nav">
      <li>
        <img class="link" @click="toggleTheme" :src="themeImg()" alt="" />
      </li>
    </ul>

    <div class="content">
      <button class="btn">按钮</button>
      <div>123</div>
    </div>
  </div>
</template>

<script lang="ts">
import { ref, watch } from 'vue';
import { getDefaultTheme, useCurrentTheme } from './utils/theme';
export default {
  name: '',
  setup() {
    const currentTheme = ref<string>(getDefaultTheme());
    const theme = useCurrentTheme();
    watch(
      currentTheme,
      (newVal, oldVal) => {
        window.localStorage.setItem('tslTheme', newVal);

        document.documentElement.classList.remove(`tsl-theme-${oldVal}`);
        document.documentElement.classList.add(`tsl-theme-${newVal}`);
      },
      {
        immediate: true,
      }
    );

    watch(
      theme,
      (newVal, oldVal) => {
        document.documentElement.classList.remove(`tsl-theme-${oldVal}`);
        document.documentElement.classList.add(`tsl-theme-${newVal}`);
      },
      {
        immediate: true,
      }
    );

    const themeImg = () => {
      if (currentTheme.value === 'light') {
        return 'https://b.yzcdn.cn/vant/dark-theme.svg';
      } else {
        return 'https://b.yzcdn.cn/vant/light-theme.svg';
      }
    };

    const toggleTheme = () => {
      currentTheme.value = currentTheme.value === 'light' ? 'dark' : 'light';
    };
    return {
      currentTheme,
      themeImg,
      toggleTheme,
    };
  },
};
</script>
<style lang="scss">
.w {
  width: 1200px;
}

.tsl-theme-light {
  background-color: var(--tsl-gray-1);
}

.tsl-theme-dark {
  background-color: var(--van-doc-black);
}

.wrapper {
  width: 100vw;
  height: 100vh;
  background: var(--tsl-background);

  .nav {
    width: 100%;
    height: 92px;
    background-color: var(--tsl-border-color);

    .link {
      width: 40px;
      height: 40px;
      .img {
        display: block;
        width: 40px;
        height: 40px;
        object-fit: cover;
      }
    }
  }

  .btn {
    width: 60px;
    height: 38px;
    color: var(--tsl-text-color-1);
    background-color: var(--tsl-background-2);
  }

  div {
    color: var(--tsl-text-color-1);
  }
}
</style>

getDefaultTheme功能: 从localStorage中读取theme 没有就默认light

useCurrentTheme功能:调用 getDefaultTheme 函数返回一个theme

接着看 toggleTheme 函数 很简单 就是赋值 dark 和 light

主要就是监听 currentTheme 给html 上绑定一个类名 theme-light 和 theme-dark

类名切换以后 颜色变量赋值不同 就导致样式颜色切换

最终就实现了主题切换的效果