从零开始手撸一个阅读器--夜间/白天主题色切换(5)

155 阅读3分钟

概述

目前能实现主题切换的方式有很多,随便一搜就一大把。但是如果在项目最开始没有考虑主题切换,而后续又要新增主题切换功能。如果处理呢?这时候再加什么scss变量、什么vuex,估计看着头都有些大了吧。下面提供两个比较简单的思路。

根元素css变量挂载

直接在根元素上挂载全局css变量,在页面中使用 var(--theme-color) 变量就行

  1. uniapp中的 App.vue:uni中App.vue本身不是页面,不能编写视图元素,也就是没有<template># App.vue/App.uvue
  2. 那应该怎么办呢?可以引入一个全局组件,在组件中把样式挂载上去,这样做有下面几个好处:
    • 可以挂载常用组件:由于uni中不能在App.vue中挂载视图元素,对于一些经常常用的组件可以挂载在这个全局组件 g-page上(如 confirm 确认框,popup 弹窗等等)。
    • 方便页面维护:可以为所有页面配置统一的样式。
    • 使用灵活:g-page 可以挂载到任何一个地方你想要使用主题色的地方。如果不想要某个页面随主题切换。不引入这个全局组件就行。
    • 使用简单:只要在页面中找到想要随主题切换的颜色,修改为css变量就行。

全局组件封装,很简单封装,复杂主题可以再进行封装

<template>
  <view
    :class="['hz-page', store.appOption.theme === 'dark' ? 'theme-dark' : 'theme-light']"
    :style="{
      '--theme-bg-color': themeStyle.bgColor,
      '--theme-bg-color-light-1': themeStyle.bgColorLight1,
      '--theme-bg-white-color': themeStyle.bgWhiteColor,
      '--theme-bg-color-deep': themeStyle.bgColorDeep,
      '--theme-bg-book-color': themeStyle.bgColorBook,

      '--theme-primary-color': themeStyle.primaryColor,
      '--theme-primary-book-color': themeStyle.primaryBookColor,
      '--theme-primary-color-light-1': themeStyle.primaryColorLight1,
      '--theme-grey-color': themeStyle.greyColor,
      '--theme-link-color': themeStyle.linkColor,

      '--theme-border-color': themeStyle.borderColor,
      '--theme-border-color-light-1': themeStyle.borderColorLight1,

      '--theme-light-icon-color': themeStyle.lightIconColor,
      '--theme-grey-icon-color': themeStyle.greyIconColor,
      '--theme-icon-active-color': themeStyle.iconActiveColor,
      '--theme-icon-link-color': themeStyle.iconLinkColor,
    }"
  >
    <slot></slot>
  </view>
</template>

<script setup lang="ts">
import { computed } from "vue";
import store from "@/store";

const pages = getCurrentPages();
let currentRoute = pages[pages.length - 1].route;
// console.log("当前页面路径:" + currentRoute);

const themeStyle = computed(() => {
  let isDark = store.appOption.theme === "dark";
  if (currentRoute === "pages/reader/index") {
    // 目前产品设计逻辑阅读器主题和app主题是分开的
    isDark = store.bookOption.theme === "dark";
  }
  return {
    bgColor: isDark ? "#2A241D" : "#FEF7F1",
    bgColorLight1: isDark ? "#3B352E" : "#F4EEE7",
    bgColorDeep: isDark ? "#1D1710" : "#f4eee7",
    bgWhiteColor: isDark ? "#38312B" : "#f1edea",
    bgColorBook: isDark ? "#4c4945" : "#c0a374",

    lightIconColor: isDark ? "#FEF7F1" : "#251e18",
    greyIconColor: isDark ? "#a8a19a" : "#554334",
    iconActiveColor: isDark ? "#EC5D57" : "#D44842",
    iconLinkColor: isDark ? "#4F5C75" : "#92afe2",

    primaryColor: isDark ? "#E9E3DC" : "#251e18",
    primaryBookColor: isDark ? "#c9c9c9" : "#482936",
    primaryColorLight1: isDark ? "#BDB7B1" : "#554e48",
    greyColor: isDark ? "#8F8982" : "#857f78",
    linkColor: isDark ? "#7E9EDA" : "#92afe2",

    borderColor: isDark ? "#5d5c5a" : "#eae0e0",
    borderColorLight1: isDark ? "#383838" : "#eee",
  };
});
</script>

页面使用

// 子组件

<template>
  <g-page>
    <g-statusbar title="关于我们"></g-statusbar>
    <view class="about"></view>
  </g-page>
</template>

<style scoped lang="scss">
.about {
  background-color: var(--theme-bg-color);
  color: var(--theme-primary-color);
}
</style>

webpack-theme-color-replace

  1. 之前公司项目中调研主题切换功能的实现的时候有了解过这个插件,这一种很不一样的实现思路
    • 大概就是在webpack构建时,将即将生成的所有css文件的内容对指定颜色的规则的css单独提取出来,再合并为一个theme-colors.css输出文件。然后在切换主题色时,下载这个文件,并替换为需要的颜色,应用到页面上。
  2. 这篇文章对动态主题的实现有更多的介绍:
  3. webpack-theme-color-replace

相关