前端 “一键换肤“ 的几种方案 | 您所在的位置:网站首页 › 一键换肤王者 › 前端 “一键换肤“ 的几种方案 |
通过切换 css选择器的方式实现主题样式的切换. 在组件中保留不变的样式,将需要变化的样式进行抽离 提供多种样式,给不同的主题定义一个对应的 CSS 选择器 根据不同主题设置不同的样式 在组件中保留不变的样式,将需要变化的样式进行抽离 提供多种样式,给不同的主题定义一个对应的 CSS 选择器 根据不同主题设置不同的样式 下面通过 vuex存储和控制全局的主题色,其代码如下: import{ createStore } from'vuex' // 创建一个新的 store 实例 conststore = createStore({ state { return{ theme: 'light' } }, mutations: { setTheme (state, payload) { state.theme = payload document.querySelector( 'body').className = payload } } }) exportdefaultstore 复制代码 在 template模板中通过 vuex中的主题设置对应类名,如头部代码如下: < template> < div:class= "['header', store.state.theme]"> < span> {{title}} < inputv-model= "checked"type= "checkbox"class= "switch"@ change= "changeTheme"/>
复制代码 下面 theme.css中通过 .light和 .dark两个类选择器来区分明亮主题和暗黑主题,并且事先准备了它们对应的样式,如下: /* light 默认主题*/ body.light{ background-color: #fff; } .header.light{ background-color: #fff; border-bottom: 1pxsolid #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: 1pxsolid rgb( 51, 50, 50); } /* dark 暗黑主题 */ body.dark{ background-color: rgb( 51, 50, 50); } .header.dark{ background-color: rgb( 51, 50, 50); border-bottom: 1pxsolid #fff; color: #fff; } .list.dark.title{ color: #fff; } .list.dark.describe{ color: rgb( 201, 201, 201); } .list.dark.left{ border: 1pxsolid #fff; background-color: #fff; } 复制代码 缺点 多种主题样式都要引入,导致代码量增大 样式不易管理 查找样式复杂 开发效率低 拓展性差 ... 多种主题样式都要引入,导致代码量增大 样式不易管理 查找样式复杂 开发效率低 拓展性差 ... 实现多套 CSS 主题样式,根据用户切换操作,通过 link标签动态加载不同的主题样式,主要解决了多个主题色被编译到一个文件中导致单个文件过大. 实现 css 部分直接拆分成 ligth.css和 dark.css两个文件: image.png 设置主题部分的 setTheme.js代码如下: exportdefaultfunctionsetTheme( theme = 'ligth') { letlink = document.querySelector( '#theme-link') lethref = "/theme/"+ theme + ".css" if(!link) { lethead = document.querySelector( 'head') link = document.( 'link') link.id = '#theme-link' link.rel = "stylesheet" link.href = href head.(link) } else{ link.href = href } } 复制代码 缺点 需要重复 CV 多份样式文件进行单独修改 没有单独提取出可变的样式部分 需要提前知道打包后的文件路径,否则可能导致主题样式引入错误 ... 需要重复 CV 多份样式文件进行单独修改 没有单独提取出可变的样式部分 需要提前知道打包后的文件路径,否则可能导致主题样式引入错误 ... 通过 body.style.setProperty(key, value)动态修改 body上的 CSS 变量,使得页面上的其他部分可以应用最新的 CSS 变量对应的样式. img 实现 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 */ [data-theme= 'dark'] { --theme-bg: rgb( 51, 50, 50); --theme-color: #fff; --theme-boder-color: #fff; } 复制代码 themeUtil.js中负责获取当前对应样式值,以及设置 body上的 CSS 变量值,如下: constdarkTheme = 'rgb(51, 50, 50)' constlightTheme = '#fff' constlightBorderTheme = '#d6d6d6' // 获取对应的主题色值 exportconstgetThemeMap = ( isLight) => { return{ 'theme-bg': isLight ? lightTheme : darkTheme, 'theme-color': isLight ? darkTheme : lightTheme, 'theme-boder-color': isLight ? lightBorderTheme : lightTheme, } } // 设置主题色值 exportconstsetTheme = ( isLight = true) => { constthemeMap = getThemeMap(isLight) constbody = document.body /* 实现方式一 */ Object.keys(themeMap).forEach( key=> { body.style.setProperty( `-- ${key}` , themeMap[key]) }) /* 实现方式二 */ // body.style.setProperty('data-theme', isLight ? 'light' : 'dark') } 复制代码 通过 var在组件中应用对应 CSS 变量,比如在头部中的使用: < stylescoped> .header { ...省略 color: var(--theme-color); border-bottom: 1px solid var(--theme-boder-color); background-color: var(--theme-bg); } ...省略
复制代码 缺点 缺点就是兼容性不好 img 兼容 通过 css-vars-ponyfill对 CSS 变量进行兼容处理,themeUtil.js中代码改变如下: importcssVars from"css-vars-ponyfill"; constdarkTheme = 'rgb(51, 50, 50)' constlightTheme = '#fff' constlightBorderTheme = '#d6d6d6' // 这里定义的 键/值 对,是为了给 cssVars 传参 exportconstgetThemeMap = ( isLight) => { return{ '--theme-bg': isLight ? lightTheme : darkTheme, '--theme-img-bg': lightTheme, '--theme-color': isLight ? darkTheme : lightTheme, '--theme-boder-color': isLight ? lightBorderTheme : lightTheme, } } exportconstsetTheme = ( isLight = true) => { constthemeMap = getThemeMap(isLight) constbody = document.body /* 实现方式一 */ Object.keys(themeMap).forEach( key=> { body.style.setProperty(key, themeMap[key]) }) /* 实现方式二 */ // body.style.setProperty('data-theme', isLight ? 'light' : 'dark') // 实现兼容方案 cssVars({ watch: true, // 添加、删除、修改 或 元素的禁用或 href 属性时,ponyfill 将自行调用 variables: themeMap, // variables 自定义属性名/值对的集合 onlyLegacy: false, // false 默认将 css 变量编译为浏览器识别的 css 样式 ;true 当浏览器不支持css变量的时候将css变量编译为识别的css }); } 复制代码 主题图片切换 实现了前面的内容之后,现在给分别给 light和 dark主题添加一个 logo,这一部分其实很简单了,下面的示例代码是基于 Vue3 进行实现的 // Header.vue < setup> import{ ref } from'vue' import{ setTheme } from'../style/themeUtil' defineProps({ title: String }) constchecked = ref( false) constlogoUrl = ref( '') constloadImg = async=> { letname = !checked.value ? 'light': 'dark' letext = !checked.value ? 'png': 'jpg' letres = awaitimport( `../assets/logo- ${name}. ${ext}` ) logoUrl.value = res.default } loadImg constchangeTheme = ( event) => { setTheme(!checked.value) loadImg } < />
< span> {{ title }} < inputv-model= "checked"type= "checkbox"class= "switch"@ change= "changeTheme"/> < /div>
复制代码 效果如下 skin.gif 最后 以上就是目前了解到一些的换肤方案,以上全部基于 css 去实现的,不过知道了原理就可以结合 less和 sass进行更好的实现。如果有更好的方案,欢迎贴在评论区进行分享!!! --- EOF --- 推荐↓↓↓返回搜狐,查看更多 |
CopyRight 2018-2019 实验室设备网 版权所有 |