「这是我参与2022首次更文挑战的第2天,活动详情查看:2022首次更文挑战」
前言
我之前写过一篇文章,关于如何实时切换主题样式,但该方式的弊端在于,每个主题,你都需要为它定义各个不同的变量,比如黑白主题,黑夜下,文字基础变量@fontColor: white;,白天时,你需要再次定义该变量@fontColor: black;,甚至任性的你,可能随意再定义一个变量名,比如@dayFontColor: black;。随着项目的扩大,这样的变量名越来越多,里面有很多重复的(不同的开发人员,命名习惯不一样),这增加了项目维护的困难性,所以我决心寻找另一种替代方案
更好的主题切换方案
利用给HTML根元素:root添加属性的方式,实现实时切换主题功能
如何做到呢?
第一步
在项目内创建modeOptions.js文件,代码如下所示:
const modeOptions = {
light: {
'--default-color-1': 'rgba(255, 255, 255, 1)',
},
dark: {
'--default-color-1': 'rgba(0, 0, 0, 1)',
}
}
export default modeOptions
在上面,我们统一了变量名称--default-color-1,在不同的主题里,它的值是不一样的
第二步
在项目内创建applyMode.js文件,代码如下所示:
import modeOptions from './modeOptions'
function render (mode) {
const rootElement = document.querySelector(':root')
const options = modeOptions[mode]
const opposite = mode === 'dark' ? 'light' : 'dark'
for (const k in options) {
rootElement.style.setProperty(k, options[k])
}
rootElement.classList.remove(opposite)
rootElement.classList.add(mode)
}
export default function applyMode (mode) {
if (mode !== 'auto') {
render(mode)
return
}
const isDarkMode = window.matchMedia('(prefers-color-scheme: dark)').matches
const isLightMode = window.matchMedia('(prefers-color-scheme: light)').matches
if (isDarkMode) render('dark')
if (isLightMode) render('light')
if (!isDarkMode && !isLightMode) {
console.log('You specified no preference for a color scheme or your browser does not support it. I schedule dark mode during night time.')
const hour = new Date().getHours()
if (hour < 6 || hour >= 18) render('dark')
else render('light')
}
}
第三步
在ThemeOptions.vue里,引入applyMode代码,代码如下所示:
<template>
<div class="theme-options">
<ul class="color-theme-options">
<li
v-for="(mode, index) in modeOptions"
:key="index"
:class="getClass(mode.mode)"
@click.prevent="selectMode(mode.mode)"
>{{ mode.title }}</li>
</ul>
</div>
</template>
<script>
import applyMode from './applyMode'
export default {
data () {
return {
modeOptions: [
{ mode: 'dark', title: '暗黑模式' },
{ mode: 'light', title: '亮色模式' }
],
currentMode: 'light'
}
},
methods: {
selectMode (mode) {
if (mode !== this.currentMode) {
this.currentMode = mode
applyMode(mode)
localStorage.setItem('mode', mode)
}
},
getClass (mode) {
return mode !== this.currentMode ? mode : `${mode} active`
},
}
</script>
第四步
在样式文件内,添加var(--default-color-1),无论.styl,还是.css都支持该语法
.font {
color: var(--default-color-1)
}
最后
成功变换了主题,且易于后期维护,完结撒花,贴一张小李子盛世美颜的图片