Skip to content

一行命令搞定项目多套主题及图片色系的切换

项目基于vue-cli3.0

需求: 项目需要配置多套主题色系,且相应的图片也需要改变,希望做到动态切换。

思考: 面对这种需求,可能之前大多都会用多套CSS和图片资源来完成,之前我们确实也有考虑过这种方式,将多套CSS及图片资源通过Nginx来配置切换,但这样仍然是会有多套资源, 与我所想的只用一套资源有所出入。其实细想下来,CSS只用一套倒好解决(用scss变量便行),只是图片更换稍微复杂点。针对这个问题,我最后选择了SVG,以下是具体的实现方式。

CSS切换

实现思路:使用scss变量,将样式配置写成js文件,借助webpack打包将js转换为scss并应用至项目。

为了项目结构清晰,新建themes文件夹用于主题配置文件,目录下新建不同文件来区分不同主题色系。

文件目录结构

variables-xx.js文件如下(格式为key -> value, 不同的js文件只需要改变对应key的value即可):

js
module.exports = {
  'themeColor': {
    'primary': '#FC1B10',
    'basic-font-family': 'PingFangSC-Regular',
    'step-bar-color': '#C9C9C9',
    'step-line-color': '#E7E7E7',
    'step-active-color': '#FC1B10',
    'tip-color': '#FC1B10'
  }
}

index.js文件如下:

js
/**
 * 获取npm切换主题命令末尾参数,导入相应主题配置文件。
 */
const processArgv = process.argv
const theme = processArgv.pop()
let styleVariables = null
switch (theme) {
  case 'xx':
    styleVariables = require('./variables-xx')
    break
  case 'xxx':
    styleVariables = require('./variables-xxx')
    break
  default:
    styleVariables = require('./variables-xxxx')
    break
}

module.exports = styleVariables['themeColor']

写好配置文件后,接下来就是将js转换成scss,并自动引入全局。

这一步我们使用webpack来完成: vue.config.js

js
const merge = require('webpack-merge')
/* 全局scss变量 */
const styleVariables = require('./src/themes/index')

module.exports = {
  chainWebpack: config => {
    config.module
    .rule('style')
    .test(/\.scss$/)
    .use(['style-loader', 'css-loader?sourceMap&minimize'])
    .loader('sass-loader')
    .options(
      merge({
        data: '@import "./src/assets/scss/variables.scss";'
           + Object.keys(styleVariables)
           .map(key => `\$${key}: ${styleVariables[key]};`)
           .join('\n'),
        sourceMap: true,
        sourceMapContents: true
      })
    )
    .end()
  }
}

'@import "./src/assets/scss/variables.scss";' 这个文件是项目中的全局scss,由于配置中只改变了色系,因此其他的全局样式单独放在了variables.scss中。使用sass-loader完成转换。

此外,在package.json中再配置一行命令,以便根据命令行参数来切换。

bash
# 开发
"serve:theme": "vue-cli-service serve --theme"
# 生产
"build:theme": "vue-cli-service build --theme"

使用如下:

bash
npm run serve:theme xx
# xx 即为对应的variables-xx.js配置文件

SVG色系切换

这个方案得益于 花裤衩这篇文章,文章写的很详细,因此以下只写实现方案,原理不再赘述。

src/components目录下编写SvgIcon组件:

点击查看代码
js
<template>
  <svg :class="[svgClass, 'theme']" aria-hidden="true">
    <use :xlink:href="svgName" />
  </svg>
</template>

<script>
export default {
  name: 'SvgIcon',
  props: {
    iconName: {
      type: String,
      required: true
    },
    /* 自定义样式 */
    iconClass: {
      type: String,
      default: ''
    }
  },
  computed: {
    svgClass() {
      if (this.iconClass) {
        return `svg-icon ${this.iconClass}`
      } else {
        return 'svg-icon'
      }
    },
    svgName() {
      return `#icon-${this.iconName}`
    }
  }
}
</script>

<style lang="scss" scoped>
.svg-icon {
  width: 100%;
  height: 100%;
//   vertical-align: -0.3em;
  fill: currentColor;
  color: #909399;
  overflow: hidden;
}

.theme {
  color: $primary;
}
</style>

src目录下新建icons文件夹:

icons目录

icons/index.js文件如下

js
import Vue from 'vue'
import SvgIcon from '@/components/SvgIcon'

/* 全局注册SvgIcon组件 */
Vue.component('svg-icon', SvgIcon)

/** 
 * 获取相应目录下的svg文件 
 * 第二个参数:为是否查找子目录 (false为不查找)
 */
const req = require.context('./svg', false, /\.svg$/)

/* 将所有文件转换成webpack context module并放进数组供webpack svg-sprite-loader获取解析 */
const requireAll = requireContext => requireContext.keys().map(requireContext)
requireAll(req)

接下来便要借助webpack了,主要是用到svg-sprite-loader,闲话少叙,上代码。 vue.config.js

js
module.exports = {
  chainWebpack: config => {
    /* set svg-sprite-loader */
    config.module
      .rule('svg')
      .exclude
      .add(path.join(__dirname, 'src/icons')) // 删除默认配置中处理svg
      .end()

    config.module
      .rule('icons')
      .test(/\.svg$/)
      .include
      .add(path.join(__dirname, 'src/icons')) // 处理svg目录
      .end()
      .use('svg-sprite-loader')
      .loader('svg-sprite-loader')
      .options({
        symbolId: 'icon-[name]'    // icons目录下,根据svg文件的文件名与symbolId一一对应。
      })
      .end()
  }
}

组件中使用SvgIcon

js
<svg-icon icon-name="test-loading" />

svg相关的配置完成后,只需将svg文件放入 src/icons/svg 目录下,就能自动转换。

至此,我们已经完成了CSS及图片资源的动态切换,写好配置文件后,一行命令便能解决。

Updated at: