现在越来越多的网站都提供了拥有换肤(切换主题)功能,如 ElementUI,既是为了迎合用户需求,或是为了凸显自己特点,因此提供了个性化定制的功能.

其实之前就想了解和实现 “一键换肤” 功能,但是由于种种原因一直拖到了现在.

css样式覆盖实现

核心

通过切换 css 选择器的方式实现主题样式的切换.

在组件中保留不变的样式,将需要变化的样式进行抽离

提供多种样式,给不同的主题定义一个对应的 CSS 选择器

根据不同主题设置不同的样式

实现

下面通过 vuex 存储和控制全局的主题色,其代码如下:

import { createStore } from 'vuex'// 创建一个新的 store 实例
const store = createStore({state () {return {theme: 'light'}},mutations: {setTheme (state, payload) {state.theme = payloaddocument.querySelector('body').className = payload}}
})export default store

在 template 模板中通过 vuex 中的主题设置对应类名,如头部代码如下:

<template><div :class="['header', store.state.theme]"><span>{{title}}</span><input v-model="checked" type="checkbox" class="switch" @change="changeTheme" /></div>
</template>

下面 theme.css 中通过 .light 和 .dark 两个类选择器来区分明亮主题和暗黑主题,并且事先准备了它们对应的样式,如下:

/* light 默认主题*/
body.light {background-color: #fff;
}.header.light {background-color: #fff;border-bottom: 1px solid #d6d6d6;color: rgb(51, 50, 50);
}.list.light .title {color: rgb(51, 50, 50);
}
.list.light .describe{color: rgb(158, 158, 158);
}.list.light .left{border: 1px solid rgb(51, 50, 50);
}/* dark 暗黑主题 */
body.dark {background-color: rgb(51, 50, 50);
}.header.dark {background-color: rgb(51, 50, 50);border-bottom: 1px solid #fff;color: #fff;
}.list.dark .title {color: #fff;
}
.list.dark .describe{color: rgb(201, 201, 201);
}
.list.dark .left{border: 1px solid #fff;background-color: #fff;
}

缺点

多种主题样式都要引入,导致代码量增大

样式不易管理

查找样式复杂

开发效率低

拓展性差

...

实现多套 CSS 主题样式

核心

实现多套 CSS 主题样式,根据用户切换操作,通过 link 标签动态加载不同的主题样式,主要解决了多个主题色被编译到一个文件中导致单个文件过大.

实现

css 部分直接拆分成 ligth.css 和 dark.css 两个文件,设置主题部分的 setTheme.js 代码如下:

export default function setTheme(theme = 'ligth') {let link = document.querySelector('#theme-link')let href = "/theme/" + theme + ".css"if (!link) {let head = document.querySelector('head')link = document.createElement('link')link.id = '#theme-link'link.rel = "stylesheet"link.href = hrefhead.appendChild(link)} else {link.href = href}
}

缺点

需要重复 CV 多份样式文件进行单独修改

没有单独提取出可变的样式部分

需要提前知道打包后的文件路径,否则可能导致主题样式引入错误

...

CSS 变量实现

核心

通过 body.style.setProperty(key, value) 动态修改 body 上的 CSS 变量,使得页面上的其他部分可以应用最新的 CSS 变量对应的样式.

实现

theme.css 中负责定义全局的 CSS 变量,代码如下:

/* 实现方式一 */
:root {--theme-bg: initial; // 背景色--theme-color: initial; // 字体色--theme-boder-color: initial; // 边框色
}====================================================/* 实现方式二 */
/* 默认值:light */
:root {--theme-bg: #fff;--theme-color: rgb(51, 50, 50);--theme-img-bg: #fff;--theme-boder-color: #d6d6d6;
}/* 暗黑:dark */
[>'dark'] {--theme-bg: rgb(51, 50, 50);--theme-color: #fff;--theme-boder-color: #fff;
}

themeUtil.js 中负责获取当前对应样式值,以及设置 body 上的 CSS 变量值,如下:

const darkTheme = 'rgb(51, 50, 50)'
const lightTheme = '#fff'
const lightBorderTheme = '#d6d6d6'// 获取对应的主题色值
export const getThemeMap = (isLight) => {return {'theme-bg': isLight ? lightTheme : darkTheme,'theme-color': isLight ? darkTheme : lightTheme,'theme-boder-color': isLight ? lightBorderTheme : lightTheme,}
}// 设置主题色值
export const setTheme = (isLight = true) => {const themeMap = getThemeMap(isLight)const body = document.body/* 实现方式一 */Object.keys(themeMap).forEach(key => {body.style.setProperty(`--${key}`, themeMap[key])})/* 实现方式二 */// body.style.setProperty('data-theme', isLight ? 'light' : 'dark')
}

通过 var() 在组件中应用对应 CSS 变量,比如在头部中的使用:

<style scoped>
.header {...省略color: var(--theme-color);border-bottom: 1px solid var(--theme-boder-color);background-color: var(--theme-bg);
}
...省略
</style>

缺点

缺点就是兼容性不好

兼容

通过 css-vars-ponyfill 对 CSS 变量进行兼容处理,themeUtil.js 中代码改变如下:

import cssVars from "css-vars-ponyfill";const darkTheme = 'rgb(51, 50, 50)'
const lightTheme = '#fff'
const lightBorderTheme = '#d6d6d6'// 这里定义的 键/值 对,是为了给 cssVars 传参
export const getThemeMap = (isLight) => {return {'--theme-bg': isLight ? lightTheme : darkTheme,'--theme-img-bg': lightTheme,'--theme-color': isLight ? darkTheme : lightTheme,'--theme-boder-color': isLight ? lightBorderTheme : lightTheme,}
}export const setTheme = (isLight = true) => {const themeMap = getThemeMap(isLight)const body = document.body/* 实现方式一 */Object.keys(themeMap).forEach(key => {body.style.setProperty(key, themeMap[key])})/* 实现方式二 */// body.style.setProperty('data-theme', isLight ? 'light' : 'dark')// 实现兼容方案cssVars({watch: true, // 添加、删除、修改 <link> 或 <style> 元素的禁用或 href 属性时,ponyfill 将自行调用    variables: themeMap, // variables 自定义属性名/值对的集合onlyLegacy: false, // false  默认将 css 变量编译为浏览器识别的 css 样式 ;true 当浏览器不支持css变量的时候将css变量编译为识别的css  });
}

主题图片切换

实现了前面的内容之后,现在给分别给 light 和 dark 主题添加一个 logo,这一部分其实很简单了,下面的示例代码是基于 Vue3 进行实现的

// Header.vue
<script setup>
import { ref } from 'vue'
import { setTheme } from '../style/themeUtil'defineProps({title: String
})const checked = ref(false)const logoUrl = ref('')const loadImg = async () => {let name = !checked.value ? 'light' : 'dark'let ext = !checked.value ? 'png' : 'jpg'let res = await import(`../assets/logo-${name}.${ext}`)logoUrl.value = res.default
}loadImg()const changeTheme = (event) => {setTheme(!checked.value)loadImg()
}</script><template><div class="header"><img class="logo" :src="logoUrl" /><span>{{ title }}</span><input v-model="checked" type="checkbox" class="switch" @change="changeTheme" /></div>
</template>

前端 一键换肤 的几种方案相关推荐

  1. 前端 “一键换肤“ 的几种方案

    作者:熊的猫 原文:https://juejin.cn/post/7063010855167721486 前端 "一键换肤" 的几种方案 前言 现在越来越多的网站都提供了拥有换肤( ...

  2. 前端 “一键换肤“ 的 N 种方案

    前端瓶子君,关注公众号 回复算法,加入前端编程面试算法每日一题群 前言 现在越来越多的网站都提供了拥有换肤(切换主题)功能,如 ElementUI[2],既是为了迎合用户需求,或是为了凸显自己特点,因 ...

  3. uniapp前端 “一键换色“ 的几种方案

    现在越来越多的网站都提供了更换主题功能,如ElementUI,既是为了迎合用户需求,或是为了凸显自己特点,因此提供了个性化定制功能. 最近刚好做了这个功能,主要通过以下几种方式实现: CSS样式覆盖 ...

  4. 前端一键换肤换肤简单探索

    效果图 默认 蓝白 方法一.如果要控制的范围不多很小的话 使用控制类名的切换 <!DOCTYPE html> <html lang="zh-CN">< ...

  5. android换肤的实现方案,一种基于Android平台的一键换肤方法与流程

    本发明属于互联网技术领域,尤其涉及一种基于Android平台的一键换肤方法. 背景技术: 换肤性能的添加在很大的程度上面提高了用户的体验感,用户可以根据自己喜好选择自己喜欢的皮肤颜色,并且我们针对不同 ...

  6. 前端项目一键换肤vue+element(ColorPicker)

    前端项目一键换肤 1.需要配色的都是用变量声明 2.增加颜色选择器 3.改变颜色,更改初始值 1.需要配色的都是用变量声明 /* 全局样式 */ body {// 无需改变--light_color_ ...

  7. android换肤的实现方案,Android应用开发之Android一键换肤功能实现

    本文将带你了解Android应用开发之Android一键换肤功能实现,希望本文对大家学Android有所帮助. < 市面上对数的App都提供换肤功能,这里暂且不讲白天和夜间模式 下图是网易云音乐 ...

  8. opengl源码 实现无缝切换图片过场_手把手讲解 Android hook技术实现一键换肤

    前言 产品大佬又提需求啦,要求app里面的图表要实现白天黑夜模式的切换,以满足不同光线下都能保证足够的图表清晰度. 怎么办?可能解决的办法很多,你可以给图表view增加一个toggle方法,参数Str ...

  9. [CSS] 自定义变量带你随心所欲,一键换肤

    认识CSS自定义变量 CSS自定义属性?听着怎么那么神奇呢,属性还可以自定义,那不是可以放肆地玩耍?我自己定义的属性浏览器都能认识? 一.基础 (一)名字和用途 其实CSS自定义属性还有很多小名,比如 ...

最新文章

  1. http://www.fx114.net/qa-24-116329.aspx
  2. mac OS下显示.htaccess等隐藏文件
  3. linux fedora 35 彻底卸载idea2021.2.2
  4. “我的一次微软面试经历”
  5. c语言编写conio库函数,c语言库函数头文件注释
  6. 关于程序化交易的点点知识
  7. RedHat Linux 5.2 网关及安全应用
  8. 【Codeforces】【Gym - 101234I】Tree Game【分类枚举】
  9. python mql4_使用MQL5将OHLC值从Python API集成到MT5
  10. 写c++好的软件_族谱家谱制作怎么写?专业的家谱族谱编辑制作软件哪个好
  11. 新站怎么提高自己网站的收录
  12. JSR 168 翻译03
  13. 试题 基础练习 数列排序
  14. 给开酒馆的小白六句忠告(下)
  15. UPS不间断电源调试注意事项
  16. 实验吧-密码学-疑惑的汉字(当铺密码)
  17. 圣斗士星矢-我至爱的动画片-Phoenix
  18. 已解决:Ubuntu下台式机前置面板耳机插孔没有声音
  19. 问题解决 | 黑金AX7020使用Petalinux定制Linux系统遇到的坑
  20. Nopcommerce 2.6 大型B2C购物平台整站开源提供

热门文章

  1. 5名员工微信群调侃领导被开除,法院这样判!
  2. Jmeter—jp@gc - Transactions per Second图表结果分析
  3. ES6:字符串转数组
  4. CEF无法加载flash的问题
  5. 华为手机鸿蒙系统手机_华为手机不要乱买,这4款是最值得选择的,全都可升级到鸿蒙系统...
  6. H5移动端网页适配iPhone x/iPhone xr/iPhone 11pro/iPhone 11/iPhone 12 机型底部小黑条
  7. 创业30载,百亿市值奥瑞金未来可期
  8. 2021.06.02会解方程的计算器
  9. UrlEncode转码
  10. wps中制作自动打勾的选择框