Young87

SmartCat's Blog

So happy to code my life!

游戏开发交流QQ群号60398951

当前位置:首页 >跨站数据

vue项目利用sass来切换主题

因工作原因,遇到了这个问题,翻查了资料,终于整出来啦,结果符合预期,特此与大家共分享

简介

看到这篇文章,大概率你是个前端工作者,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里面当做全局来用,这样当组件内部需要主题的属性值时,我们也可以取到。

定义我们的sass mixin

这里我们新建一个文件夹叫做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的混入呢,混入到每一个组件内,答案当然是有的。

使用sass-resources-loader实现全局混入

首先肯定是安装了,执行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变量了

除特别声明,本站所有文章均为原创,如需转载请以超级链接形式注明出处:SmartCat's Blog

上一篇: 数据结构与算法:Python语言实现--Python入门 数据结构与算法 Python 语言实现 课后答案

下一篇: es6中的Map对象

精华推荐