真实落地方案,我们落地的方案颜色使用的是css变量方式这个方案,图片就使用的下面那一种,使用起来目前还没发现什么问题。方案如下:
颜色适配
css变量方式
动态改变html上绑定的变量
1. 配置全局变量主题颜色
:root[data-theme="blue"] {
--color-bg: rgba(11, 36, 77, 1);
--color-border: rgba(255, 255, 255, 0.08);
--color-text: rgba(255, 255, 255, 0.9);
--color-share: rgba(255, 140, 0, 1);
}
:root[data-theme="white"] {
--color-bg: rgba(255, 255, 255, 1);
--color-border: rgba(0, 0, 0, 0.05);
--color-text: rgba(51, 51, 51, 1);
--color-share: rgba(0, 140, 0, 1);
}
:root[data-theme="black"] {
--color-bg: rgba(31, 31, 31, 1);
--color-border: rgba(255, 255, 255, 0.05);
--color-text: rgba(255, 255, 255, 0.9);
--color-share: rgba(180, 10, 0, 1);
}
2. 页面初次加载和主题切换
主题的str存为响应式数据,便于后续拓展
import { defineStore } from "pinia";
import { ref } from "vue";
export const useThemeStore = defineStore('theme', () => {
const theme = ref(localStorage.getItem('theme') || 'blue');
function initTheme() {
const themeStr: string = localStorage.getItem('theme') || 'blue';
// 初始化主题变量
document.documentElement.setAttribute('data-theme', themeStr);
}
function switchTheme(theme: string) {
// 切换主题变量
document.documentElement.setAttribute('data-theme', theme);
// 保存主题到本地存储
localStorage.setItem('theme', theme);
}
return { theme, initTheme, switchTheme }
})
3. 模板中使用主题
依旧是两种方案,方案一使用动态样式的方法,方案二使用动态类的方法
方案一
<div :style="{ color: 'var(--color-share)' }">测试文字二,模板中使用主题色</div>
方案二
<div class="data" :class="handleColor(iten.change_pct)">{{
formatNumberToPercentage(iten.change_pct) }}</div>
const handleColor = (value: number | undefined | null) => {
const num = value ?? 0
if (num > 0) {
return "redColor";
} else if (num < 0) {
return "greenColor";
} else {
return "whiteColor";
}
};
.redColor {
color: var(--color-share1) !important;
}
.greenColor {
color: var(--color-share2) !important;
}
.whiteColor {
color: var(--color-share3) !important;
}
4. 缺点
在主题切换的时候变化内容较大,可能会出现短暂白屏时间
css预处理器方案
核心要点就是一开始就要将主题样式全部设置好,比如我这种3个主题就要编译出来3套css
方案各有优缺点,这种方案自己研究下
1. 具体实现
通过预处理器变量和mixin,在构建时生成多套主题CSS文件
2.缺点
- 可能首屏白屏时间过长
- 团队之间要规范好,还有各种混入要提前处理好
- 感觉这个有点麻烦,还是推荐方案一
图片适配
主题的适配还有图片相关的适配,这种应该如何处理
这种一般比较简单,看图片是放服务器还是放各大厂商上面,比如阿里oss,不管放哪里,思路都是一样的
- 创建3个文件夹,blue/white/black,分别将不同主题的图片传到不同文件夹下面
- 从store中拿到相对应的主题字符串,然后根据这个字符串来拼接对应的图片地址
- 相对应的获取图片代码大概类似下面,我写的比较简单,可以适当拓展
export function imgUrl(iconName: string) {
const useThemeInfo = useThemeStore()
const { theme } = storeToRefs(useThemeInfo)
return `${href}/${theme}/${iconName}`;
}
这个函数直接放到模板中,因为里面有响应式属性,所以主题切换的时候是响应式的,但是有一个注意点
场景:表头有2块区域对应6个卡片,对应不同的背景色,然后循环设置背景色,我们存到数组中然后循环设置背景色,这种情况会丢失响应式,这种记得要特殊处理,使用computed包一层
<div class="card-item" v-for="(cardItem, idx) in Data[item]"
:key="cardItem.id"
:style="{ backgroundImage: `url(${rankingIconMap[index][idx]})` }"></div>
const rankingIconMap = computed(() => [
[imgUrl('pic_b_55a@3x.png'), imgUrl('pic_b_55b@3x.png'), imgUrl('pic_b_55c@3x.png')],
[imgUrl('pic_b_54a@3x.png'), imgUrl('pic_b_54b@3x.png'), imgUrl('pic_b_54c@3x.png')]
])