小程序多主题方案
自由的 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
组件的,来切换一些原生的样式
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
变量的效果。
通过这 2
个 props
,你既可以通过 mode
的切换,把多个主题以及对应的变量值全部给写在你自己的 css
中,然后通过切换mode
,触发样式的覆盖来切换主题,这种是为静态的切换。
又可以通过设置 vars
的值去动态的覆盖和切换,比如从服务端获取css
变量的值,然后set
进组件中,这显然是非常灵活的,这种是为动态的切换。
现在有了这个组件,我们就可以用它去包裹每一个页面了。
然后下一步,自然是要我们的页面和组件,都去应用那些我们设计的 css
变量了。
这一块可以参考下方链接中的动态调整系统主题色(4)
中的CssVar
方案,里面也有和 tailwindcss
相结合的部分,也欢迎阅读动态调整web系统主题
系列文章,并与在下进行探讨。
动态调整主题参考链接
- 动态调整web系统主题? 看这一篇就够了
- 动态调整web主题(2) 萃取篇
- 动态调整web主题(3): 基于tailwindcss插件的主题色生成方案
- 动态调整系统主题色(4): CssVar 与 Variant 方案的探索
参考示例
微信上搜索 tailwind
(未交 30
元个人资质费用,已无法搜索),进入小程序即可,小程序码:
实现源代码详见: weapp-tailwindcss/tailwindcss-weapp