《Vue》聊一聊实际项目中前端的几种皮肤实现和优缺点

前言

在现代大前端领域中,换肤功能已经逐渐成为几乎所有应用的标配,尤其是暗夜模式被推广之后,皮肤功能就正式走到了大众的视野,同样,在web领域尤其是后台管理系统中皮肤功能也由此几乎成为了标配,恰好最近在做的东西同样要包含这样一套机制~

那么今天就实际聊一聊web中多个的皮肤功能实现方案的优缺点,本文的方案几乎来自于各位大佬的博文,以下内容仅以个人角度浅析并实践后的分享,各方案本身并不存在优劣,只是根据使用环境才引出的各种优缺点

原理

首先来说一说换肤的原理,个人了解下来之后无非就是两种:

  1. 样式覆盖,简单的说就是利用CSS权重的优先级,高权重的样式覆盖掉低权重样式,使得位置,颜色等等都发生了变化;
  2. 变量替换,这种就是充分利用SCSS、LESS、或者CSS的变量机制,利用变量的值的不同做一个替换,使得对于的皮肤功能发生变化;

这两种其实我个人感觉并没有本质上的差别;

换肤方案

第一种:CSS样式覆盖

在这一种方案中,利用的就是CSS本身的功能就可以实现,并没有使用到SCSS、LESS等(当然SCSS和LESS那肯定是可以做的,CSS预处理器的功能确实在CSS的基础上进化了许多,只是说这种方式利用CSS就可以实现了)

示例

大致示例代码如下,以Vue为例:

<!-- 这是一个登陆界面的代码 -->
<template>
    <div class="page-account" :class="theme">
        <Login @on-submit="handleSubmit" class="login-conatiner">
            <UserName name="username" value="admin" class="login-username" />
            <Password name="password" class="login-password" value="admin" enter-to-submit />
            <div class="page-account-auto-login login-conatiner-light">
                <Checkbox v-model="autoLogin" size="large">{
    
    {
    
    
                    $t("page.login.remember")
                }}</Checkbox>
                <a href="">{
    
    {
    
     $t("page.login.forgot") }}</a>
            </div>
            <Submit>{
    
    {
    
     $t("page.login.submit") }}</Submit>
        </Login>
    </div>
</template>

如代码所示,给代码绑定了一个class,class的值也就是样式名,来自于vuex或者当前界面的计算的值,也就是皮肤的主样式名,之后便是编写对应类名的CSS代码,大致如下

<style scoped>
/** 白天模式 */
.light .login-conatiner {
    
    
    background: #ffffff;
    color: #333333;
    font-size: 1rem;
}
.light .login-username {
    
    
    background: #ffffff;
    color: #333333;
    font-size: 1rem;
}
.light .login-password {
    
    
    background: #ffffff;
    color: #333333;
    font-size: 1rem;
}

/** 夜晚模式 */
.dark .login-conatiner {
    
    
    background: #333333;
    color: #ffffff;
    font-size: 1rem;
}
.dark .login-username {
    
    
    background: #333333;
    color: #ffffff;
    font-size: 1rem;
}
.dark .login-password {
    
    
    background: #333333;
    color: #ffffff;
    font-size: 1rem;
}
</style>

当Vuex中皮肤名发生变化后,那么皮肤名下对应的类名的值都会随之发生变化,那么其样式会覆盖掉原生样式,这样便达到了换肤的效果;

优点

这种皮肤方案的优点个人觉得非常明显,就是修改便捷,并且结构非常清晰,哪里要修改就直接修改,毕竟优秀的代码不仅仅要考虑代码量,原理,可维护性等各种因素,还要考虑上手难度,其简单的实现即使一个新接手项目的人,在稍微熟悉了之后便可以直接开始添加修改了;

缺点

多套皮肤会有多套样式表,代码量大,开发效率比较低,并且如果是多人协同开发的,可能在一开始就要有所约定,这种方案最适合的项目其实是中小型项目,一两个前端开发沟通成本低;

优化

实际项目中肯定是还可以优化的,比如统一定义颜色为变量,其实不止LESS,SASS,在CSS3中也有变量功能:

:root {
    
    
  --theme-light-bg: #ffffff; // 背景色
  --theme-light-color: #333333; // 字体色
  --theme-light-border: #e1e1e1; // 边框色
}

这样便可以统一管理颜色,后续新增一套皮肤只需要新增皮肤对应的一组颜色就可以了,还是比较方便的,同样在LESS或SASS中管理就更为方便了,这些预处理器不仅仅提供了变量功能,还提供了混入,嵌套,甚至函数的功能…一旦使用上了这些,其实这种方案我个人觉得不失为一种实际项目中非常可行功能;

第二种:变量替换

这种方式其实某种程度感觉和第一种差不多,最大的区别在于第一种利用的是权重是去覆盖,而第二种就更为直接是去设置,核心函数其实只有一个:

// 设置CSS变量值
document.body.style.setProperty(变量名,变量值);

这个函数可以设置根节点上对应CSS变量的值,我们只要改变了这个值,那么所有引用这个值的地方都会发生变化,从而达到换肤的效果;

示例

比如我们设置了一组CSS变量

// 默认值
:root {
    
    
  --theme-bg: #fff;
  --theme-color: rgb(51, 50, 50);
  --theme-size: 1rem;
}

在之后的项目中,我们通通是使用的这组变量

<style scoped>
.login-conatiner {
    
    
    background: var(--theme-bg);
    color: var(--theme-bg);
    font-size: var(--theme-size);
}
.login-username {
    
    
    background: var(--theme-bg);
    color: var(--theme-bg);
    font-size: var(--theme-size);
}
.login-password {
    
    
   background: var(--theme-bg);
    color: var(--theme-bg);
    font-size: var(--theme-size);
}
</style>

差不多就是这样,在实际书写样式的时候统一使用变量,之后,存在一个处理样式的js文件

const light = 'rgb(51, 50, 50)'
const dark = '#d6d6d6'

/**
 * 获取一组皮肤变量
 * @param {Boolean} state 样式判断条件
 */
function getTheme(state) {
    
    
    return {
    
    
        "theme-bg": state ? light : dark,
        "theme-color": state ? light : dark,
        "theme-size": state ? light : dark,
    };
}

/**
 * 设置变量值
 * @param {Boolean} state 样式判断条件
 */
function setTheme(state = true) {
    
    
    const theme = getTheme(state);

    Object.keys(theme).forEach((key) => {
    
    
        document.body.style.setProperty(`--${
      
      key}`, themeMap[key]);
    });
}

在这个js文件中,我们可以定义获取和设置函数,获取函数主要根据参数获取对于的皮肤的值,而设置函数则主要负责设置根节点上变量的值;
一旦触发皮肤切换功能,那么直接可以通过setTheme这个函数设置根节点的变量值,从而实现换肤的效果;

优点

调理清晰,不需要书写很多套样式,只需要书写几种颜色,剩下的都是根据色值自动填充;

缺点

由于是CSS3之后新增的属性,兼容性还是比较差的,IE就直接不支持了,具体如下:
在这里插入图片描述

优化

这种方案优化主要是两个方向,第一个是接入LESS或者SASS,利用这些预处理器的特性,去更好的实现CSS代码的复用性,可读性,可维护性等等;
另一个就是解决兼容性问题了,这里介绍一个工具:css-vars-ponyfill,npm地址:https://www.npmjs.com/package/css-vars-ponyfill,具体用法可以度娘搜一下,一大堆教程;

参考

阮一峰老师:《CSS变量教程》;
MDN:《使用CSS自定义属性(变量)》;

小结

总体来看,换肤的方向大致都是基于这两种方案实现的,只是实现的方式有的利用了CSS的预处理器使得其封装性,实用性得到了进一步的提升,延伸出来的优秀的落地方案其实还有很多,比如ElementUI中的皮肤实现非常非常厉害,值得学习;

猜你喜欢

转载自blog.csdn.net/zy21131437/article/details/123446340
今日推荐