Vue 换肤的示例实践


Posted in Javascript onJanuary 23, 2018

最近公司做的项目得到一个网站换肤的需求,也就是切换主题。那么如何切换主题色呢?切换主题色其实就是切换 CSS,然而在项目中不仅只有 CSS 需要换肤,图标和图片也需要跟随主题进行切换。于是,写一篇文章来记录下 Vue 中实现换肤的过程,先看下效果吧。

Vue 换肤的示例实践

本文主要分三部分:CSS 切换,图标切换和图片切换。

CSS切换

关于 CSS 颜色的切换,我通过搜索,参考了ElementUI 的方案,总的来说分为四步

在 static 目录下新建一个 theme.css 文件,将需要替换的 CSS 声明在此文件中

.side-bar {
 background: linear-gradient(#B7A3FF, #879FFF) !important;
}

.side-bar .account-info {
 background: #8981D8 !important;
}

声明所有可选的主题,每种颜色都对应于一个关键词,方便区分

colors: [{
 themeId: 1,
 familyPrimary: '#B7A3FF',
 familySecondary: '#879FFF',
 sideBarTop: '#8981D8'
}, {
 themeId: 2,
 familyPrimary: '#FDC5C5',
 familySecondary: '#F070A0',
 sideBarTop: '#E7829F'
}, {
 themeId: 3,
 familyPrimary: '#414D6C',
 familySecondary: '#2D1E3C',
 sideBarTop: '#423C50'
}]

通过 AJAX 获取 theme.css ,将颜色值替换为关键词。

getFile(`/static/theme.css`)
  .then(({data}) => {
   let style = getStyleTemplate(data)
  })

function getStyleTemplate (data) {
 const colorMap = {
  '#B7A3FF': 'familyPrimary',
  '#879FFF': 'familySecondary',
  '#8981D8': 'sideBarTop'
 }
 Object.keys(colorMap).forEach(key => {
  const value = colorMap[key]
  data = data.replace(new RegExp(key, 'ig'), value)
 })
 return data
}

把关键词再换回刚刚生成的相应的颜色值,并在页面上添加 style 标签

getFile(`/static/theme.css`)
  .then(({data}) => {
   let style = getStyleTemplate(data)
   writeNewStyle(style, this.color)
  })

function writeNewStyle (originalStyle, colors) {
 let oldEl = document.getElementById('temp-style')
 let cssText = originalStyle
 Object.keys(colors).forEach(key => {
  cssText = cssText.replace(new RegExp(key, 'ig'), colors[key])
 })
 const style = document.createElement('style')
 style.innerText = cssText
 style.id = 'temp-style'
 oldEl ? document.head.replaceChild(style, oldEl) : document.head.appendChild(style)
}

图标切换

由于项目刚开始做的时候并没有考虑到换肤的需求,于是所有图标都是采用 img 标签的方式引用的,

<img src="../../assets/icon_edit.svg">

这样就导致无法给 icon 动态切换颜色了,所以,我决定改为 font 文件的方式来使用图标。这里推荐一个网站 icomoon ,这个网站可以轻松地将图片转换成 font 文件。图标也非常适合通过 font 的方式来使用,我们可以更加方便的修改图标的大小和颜色。

通过在线转换,我们将下载下来的 font 文件放入项目中,并新建一个 CSS 文件来声明所有图标。

@font-face {
 font-family: 'icomoon';
 src: url('../assets/fonts/icomoon.eot?vpkwno');
 src: url('../assets/fonts/icomoon.eot?vpkwno#iefix') format('embedded-opentype'),
 url('../assets/fonts/icomoon.ttf?vpkwno') format('truetype'),
 url('../assets/fonts/icomoon.woff?vpkwno') format('woff'),
 url('../assets/fonts/icomoon.svg?vpkwno#icomoon') format('svg');
 font-weight: normal;
 font-style: normal;
}

[class^="icon-"], [class*=" icon-"] {
 /* use !important to prevent issues with browser extensions that change fonts */
 font-family: 'icomoon' !important;
 speak: none;
 font-style: normal;
 font-weight: normal;
 font-variant: normal;
 text-transform: none;
 line-height: 1;
 vertical-align: sub;

 /* Better Font Rendering =========== */
 -webkit-font-smoothing: antialiased;
 -moz-osx-font-smoothing: grayscale;
}

.icon-edit:before {
 content: "\e900";
}

之后就能通过 CSS 类名的方式来引用图标了。

<span class="icon-edit"></span>

为了使主题生效,我们也需要把图标的 CSS 写入 theme.css 文件中

.icon_edit:before {
 background-image: linear-gradient(-135deg, #879FFF 0%, #B7A3FF 100%);
}

图片切换

项目中还存在很多占位图或者其他图片会随着主题的变化而变化。通过引入所有图片,并用文件名来区分不同主题所对应的图片。在点击切换主题时,切换到主题所对应的文件,就能实现图片切换了。为此,我写了一个 mixin,并在组件中引入 mixin。

<img :src="userImg || placeholderWoman">

placeholderMixin

let callback
const placeholderMixin = {
 data () {
  return {
   placeholderWoman: '',
   placeHolderNoReply: '',
   placeHolderNothing: ''
  }
 },
 created () {
  let themeId = localStorage.getItem('themeId')
  let theme = themeId2Name(themeId)
  this.setThemeValue(theme)
  callback = (theme) => {
   this.setThemeValue(theme)
  }
  bus.$on('changeTheme', callback)
 },
 destroyed () {
  bus.$off('changeTheme', callback)
 },
 methods: {
  setThemeValue (theme) {
   this.placeholderWoman = require(`@/assets/placeholder_woman_${theme}.svg`)
   this.placeHolderNoReply = require(`@/assets/icon_noreply_${theme}.svg`)
   this.placeHolderNothing = require(`@/assets/icon_nothing_${theme}.svg`)
  }
 }
}

在点击切换主题时,会发射一个 changeTheme 事件,各组件接收到 changeTheme 事件,就会为图片重新赋值,也就达到了切换图片的效果。

let theme = themeId2Name(this.themeId)
bus.$emit('changeTheme', theme)

这样也就达到了切换主题的效果,但是这种方法需要在几乎所有业务组件中引入 mixin,如果有更好的方法,欢迎与我交流。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Javascript 相关文章推荐
javascript 尚未实现错误解决办法
Nov 27 Javascript
js字符编码函数区别分析
Dec 28 Javascript
JS 实现导航栏悬停效果(续)
Sep 24 Javascript
jquery xMarquee实现文字水平无缝滚动效果
Apr 29 Javascript
JavaScript中的函数模式详解
Feb 11 Javascript
详解JavaScript for循环中发送AJAX请求问题
Jun 23 Javascript
关于Javascript中defer和async的区别总结
Sep 20 Javascript
javascript简单链式调用案例分析
May 10 Javascript
webpack学习--webpack经典7分钟入门教程
Jun 28 Javascript
AngularJS实现进度条功能示例
Jul 05 Javascript
微信小程序首页的分类功能和搜索功能的实现思路及代码详解
Sep 11 Javascript
Node.js 的 GC 机制详解
Jun 03 Javascript
js和jQuery以及easyui实现对下拉框的指定赋值方法
Jan 23 #jQuery
Vue 拦截器对token过期处理方法
Jan 23 #Javascript
浅谈React + Webpack 构建打包优化
Jan 23 #Javascript
vue组件编写之todolist组件实例详解
Jan 22 #Javascript
基于openlayers4实现点的扩散效果
Aug 17 #Javascript
vue-cli启动本地服务局域网不能访问的原因分析
Jan 22 #Javascript
webpack引入eslint配置详解
Jan 22 #Javascript
You might like
PHP教程 基本语法
2009/10/23 PHP
php pack与unpack 摸板字符字符含义
2009/10/29 PHP
php带密码功能并下载远程文件保存本地指定目录 修改加强版
2010/05/16 PHP
如何使用FireFox插件FirePHP调试PHP
2013/07/23 PHP
PHP记录页面停留时间的方法
2016/03/30 PHP
PHP实现时间比较和时间差计算的方法示例
2017/07/24 PHP
jQuery 使用手册(二)
2009/09/23 Javascript
JQuery Tab选项卡效果代码改进版
2010/04/01 Javascript
删除select中所有option选项jquery代码
2013/08/12 Javascript
javascript图片相似度算法实现 js实现直方图和向量算法
2014/01/14 Javascript
JSONP跨域的原理解析及其实现介绍
2014/03/22 Javascript
JS+CSS实现Li列表隔行换色效果的方法
2015/02/16 Javascript
JavaScript模块化开发之SeaJS
2015/12/13 Javascript
javaScript事件机制兼容【详细整理】
2016/07/23 Javascript
js实现非常棒的弹出div
2016/10/06 Javascript
微信小程序 跳转方式总结
2017/04/20 Javascript
react-native组件中NavigatorIOS和ListView结合使用的方法
2017/09/30 Javascript
nodejs高大上的部署方式(PM2)
2018/09/11 NodeJs
详解vue-cli 脚手架 安装
2019/04/16 Javascript
了解重排与重绘
2019/05/29 Javascript
VUE使用axios调用后台API接口的方法
2020/08/03 Javascript
Python类的基础入门知识
2008/11/24 Python
Python深入学习之特殊方法与多范式
2014/08/31 Python
Python THREADING模块中的JOIN()方法深入理解
2015/02/18 Python
Python类方法__init__和__del__构造、析构过程分析
2015/03/06 Python
python求解水仙花数的方法
2015/05/11 Python
python3访问字典里的值实例方法
2020/11/18 Python
PHP笔试题
2012/02/22 面试题
2013年大学生的自我鉴定
2013/10/24 职场文书
财务出纳岗位职责
2014/02/03 职场文书
授权委托书格式
2014/07/31 职场文书
地道战观后感500字
2015/06/04 职场文书
Golang全局变量加锁的问题解决
2021/05/08 Golang
Python批量解压&压缩文件夹的示例代码
2022/04/04 Python
R9700摩机记
2022/04/05 无线电
字节飞书面试promise.all实现示例
2022/06/16 Javascript