因工作原因,遇到了这个问题,翻查了资料,终于整出来啦,结果符合预期,特此与大家共分享
看到这篇文章,大概率你是个前端工作者,css肯定很熟悉,sass或者less应该也用过(嗯,我就当你用过了),不然我没法写了啊,需要大家稍微理解sass中的一些语法,比如 @mixin 混合指令(Mixin)用于定义可重复使用的样式,避免了使用无语意的 class,偷懒神器,但是很容易导致滥用,导致代码臃肿 @include 用于引用混合样式,格式是在其后添加混合名称,以及需要的参数 $命名的变量 最普遍的用法,变量以美元符号开头,赋值方法与 CSS 属性的写法一样 知道这些差不多已经够用啦,想了解更多,更详细的同学,可以扒拉扒拉sass的官网 sass官网 当然你还需要了解css的自定义属性
<html data-theme="white"></html> html{ color: blue; [data-theme = 'white'] { color: red; } }如代码所示,这样生效的是自定义属性,而且是优先生效,即
html{ [data-theme = 'white'] { color: red; } color: blue; }生效的依然是我们定义的自定义属性,好了普及完毕,接下来进入正题
首先我们先设置一下自定义属性,这里我们把自定义属性设置到html根节点上,
//若本地存在主题则应用该主题,否则默认白色主题 currentTheme: localStorage.getItem('DATA-THEME') ? localStorage.getItem('DATA-THEME'): 'white' setAttribute(theme) { //给html节点设置自定义属性 window.document.documentElement.setAttribute('data-theme', theme) //本地存下来用户设置的主题 localStorage.setItem('DATA-THEME', theme) }当用户选择主题背景时,我们就来动态的设置下我们的自定义属性,当然我们可以把它写进vuex里面当做全局来用,这样当组件内部需要主题的属性值时,我们也可以取到。
这里我们新建一个文件夹叫做theme,放在assets下,在建两个scss文件,如图 theme.scss 这里存放我们的全局配置颜色值,方便管理和维护
// 导入配置 @import "./theme-mixin.scss"; /*-------------------------全局----------------------*/ $color_green: #00b478; // 绿 $color_red: #eb444e; // 红 $color_border: #e4e9eb; // 分割线滚动条 $color_font: #101b21; // 一级字体 $color_font2: #58707b; // 二级字体 $color_font3: #9ab2bc; // 三级字体 $color_bg: #ffffff; // 卡片背景 $color_bg2: #f5f8f9; // 全局背景 $color_bg3: transparent; // 透明 /*-------------------------全局----------------------*/一半情况下,这样足够我们使用了,但是,架不住设计师们脑洞啊,有的是组件特有怎么办,或者对现有项目进行主题切换,颜色值特乱。 为了防止这种情况,我们可以在配置里面分路由模块进行颜色值添加,因为路由模块肯定是不一样的,这样就算多人协作开发也不会互相影响,也能解决各个组件内的问题
/*-------------------------home----------------------*/ // 白色主题 $home_white_font_color: #000; $home_white_bg_color: #000; // 黑色主题 $home_black_font_color: #fff; $home_black_bg_color: #fff; /*-------------------------home----------------------*/这样写,哪个主题的颜色就能很快找到,字体的font,背景的bg,还有边框border,虽然会重复书写好多颜色值,但是一目了然,而且方便后期维护,以及后期添加的新主题。 theme-mixin.scss 这里则写着我们的css逻辑
/* --------------------------------设置字体大小---------------------- */ @function pxTorem($px) { //只需要设置下根节点的$root_font_size就可以把px转成rem @return $px / $root_font_size+rem; } /* ----------------------------------设置字体大小------------------- */ /* --------------------------------设置字体颜色---------------------- */ @mixin font_color( $font_color_black, //黑色主题时字体颜色 $font_color_white, //白色主题时字体颜色 $font_weight_black: normal, //是否需要加粗 $font_weight_white: normal //是否需要加粗 ) { // 主题为黑色时的字体颜色 [data-theme="black"] & { //记住这里一定要有 & 符号,否则样式不生效 color: $font_color_black; font-weight: $font_weight_black; } // 主题为白色时的字体颜色 [data-theme="white"] & { color: $font_color_white; font-weight: $font_weight_white; } } /* ----------------------------------设置字体颜色------------------- */ /* --------------------------------设置背景颜色---------------------- */ @mixin bg_color($bg_color_black, $bg_color_white) { // 主题为黑色时的背景颜色 [data-theme="black"] & { background-color: $bg_color_black; } // 主题为白色时的背景颜色 [data-theme="white"] & { background-color: $bg_color_white; } } /* ----------------------------------设置背景颜色------------------- */好了,逻辑写完了,我们只需要在改变主题的scss文件里,引入我们配置的theme.scss就行,
//设置字体,当然不需要加粗的时候,不需要写后两个参数,以为我们写了noamal默认值 @include font_color($exchange_font_color_white, $exchange_bg_color_black, normal, bold); //设置字体,传入黑色主题的背景颜色和白色主题的背景颜色 @include bg_color($exchange_bg_color_black, $exchange_bg_color_white);这样我们就能改变主题啦,但是又有一个问题出现了,细心的同学发现了,我们颜色表里配置的还有border的颜色,这怎么办,难不成又要写一个border的混入?万一它不是border,而是border-right或者left单一的呢?还有万一我需要加权重!important怎么办?这里,笔者写了一个适用于这些的混入,如下
/* --------------------------------自定义设置属性---------------------- */ //第一个为属性值,第二个为黑色主题时的颜色,第三个参数为白色主题时的参数,最后一个参数为接受不确定的参数个数,类似于reset参数 @mixin setAttribute($attribute, $bg_color_black, $bg_color_white, $value...) { // 主题为黑色时的背景颜色 [data-theme="black"] & { #{$attribute}: $bg_color_black $value; //#{}为插值语法解析成字符串 多用在属性值以及选择器上比如#{border}-right: 1px solid #fff; } // 主题为白色时的背景颜色 [data-theme="white"] & { #{$attribute}: $bg_color_white $value; } } /* ----------------------------------自定义设置属性------------------- */那么该怎么用呢?
//以此传入属性值,颜色值,以及其余配置,当然最后一个参数也可以省略不写 //当参数为多个时 @include setAttribute(border, transparent, $exchange_font_color_white3, 1px solid); //当参数为加权时 @include setAttribute(background, transparent, $exchange_font_color_white3, !important); //当无参数时 @include setAttribute(background, transparent, $exchange_font_color_white3); //当颜色值为渐变时 @include setAttribute(border, linear-gradient(#14232a,#16252d,#16262e), $exchange_font_color_white3, 1px solid); //当有背景图片时 当没有属性值时或者采用默认属性值时,置为空即可 @include setAttribute(background, url('~@/assets/1.png') no-repeat center, '')当然这种方法也兼容上面的字体颜色设置以及背景设置,ok,大功告成。
嗯,好虽好但是每个组件都引入下,不得累死个人呀,sass有没有类似于vue的混入呢,混入到每一个组件内,答案当然是有的。
首先肯定是安装了,执行yarn add sass-resources-loader -D进行安装。接下来是重点。就是我们还需要配置一下loader,在vue.config.js里面
chainWebpack: config => { const oneOfsMap = config.module.rule('scss').oneOfs.store; oneOfsMap.forEach(item => { item .use('sass-resources-loader') .loader('sass-resources-loader') .options({ // Or array of paths resources: [ 'src/assets/scss/theme-mixin.scss', 'src/assets/scss/theme-var.scss' ] }) .end(); }); }现在就可以在任意组件内使用定义好的混入mixin以及全局sass变量了
