跳到主要内容

小程序多主题方案

自由的 web 方案

对于 web 来说,多主题色的需求是非常常见的,比如 暗黑模式 就是一个极其常见的需求,

web 上的解决方案无非就是,通过动态切换 css 变量的值达成效果,或者通过 .dark / [data-theme] 选择器,包裹暗黑模式下页面和组件的样式,通过增加选择器的优先级,来覆盖默认的样式等等...

那么小程序的方案应该怎么去实现呢?

答案就是有 page-meta 页面属性配置节点 的情况下,优先使用它的 page-style 属性,进行 css 变量的切换

没有 page-meta 页面属性配置节点的情况下,我们只能通过配置单个 view 组件的样式变量,来进行主题色的切换

方案的设计和实现

切换多主题主要依赖 css 变量切换,所以我们只要依照这个设计去实现即可

1. 页面属性配置节点 page-meta

利用 page-meta 页面属性配置节点的 page-style 属性,来进行 css 变量的切换

另外我们也可以通过 page-meta 组件的,来切换一些原生的样式

page-meta 页面属性配置节点

2. 自己实现 css 变量切换组件

首先既然我们无法利用节点的变量切换来达成效果,但是我们可以通过组件的特性,即数据的响应式和插槽来达成效果。

我们可以设计一个 ConfigProvider 组件,它拥有一个dom节点,内部是一个插槽

其中那个dom节点就是我们主题相关变量寄居在的节点,而这个组件往往会作为一个根组件,在每个页面中被使用,去包裹我们真正的业务页面

甚至我们可以再设计一个 BaseLayout 这样的组件,去包含每个页面公共的部分,再在其中去引用 ConfigProvider,然后做一层插槽的透传即可。

实现

这里我以 vue 的语法作为示例,因为我个人认为它比 react原生 更容易让新手看懂

ConfigProvider的实现:

<template>
<view :class="[mode]" :style="styleObj">
<slot></slot>
</view>
</template>

<script lang="ts">
import { defineComponent, computed, PropType } from 'vue'
// import store from '@/store'
export default defineComponent({
props: {
vars: {
type: [Object]
},
mode: {
type: [String] as PropType<'light' | 'dark'>,
default: 'light' // 这里你可以使用 store.state.mode 这样的值来获取用户的配置
}
},
setup(props) {
const styleObj = computed(() => {
return Object.assign({}, props.vars)
})
return {
styleObj
}
}
})
</script>

其中,mode 这个 prop 用来模拟实现了 <html data-theme="<theme>" class="<theme>"></html> 的效果,而 vars 则用来模拟实现 js api 设置 css 变量的效果。

通过这 2props,你既可以通过 mode 的切换,把多个主题以及对应的变量值全部给写在你自己的 css中,然后通过切换mode,触发样式的覆盖来切换主题,这种是为静态的切换。

又可以通过设置 vars的值去动态的覆盖和切换,比如从服务端获取css变量的值,然后set进组件中,这显然是非常灵活的,这种是为动态的切换。

现在有了这个组件,我们就可以用它去包裹每一个页面了。

然后下一步,自然是要我们的页面和组件,都去应用那些我们设计的 css 变量了。

这一块可以参考下方链接中的动态调整系统主题色(4)中的CssVar方案,里面也有和 tailwindcss 相结合的部分,也欢迎阅读动态调整web系统主题 系列文章,并与在下进行探讨。

动态调整主题参考链接

  1. 动态调整web系统主题? 看这一篇就够了
  2. 动态调整web主题(2) 萃取篇
  3. 动态调整web主题(3): 基于tailwindcss插件的主题色生成方案
  4. 动态调整系统主题色(4): CssVar 与 Variant 方案的探索

参考示例

微信上搜索 tailwind(未交 30 元个人资质费用,已无法搜索),进入小程序即可,小程序码:

tailwind

实现源代码详见: weapp-tailwindcss/tailwindcss-weapp