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 相关文章推荐
VC调用javascript的几种方法(推荐)
Aug 09 Javascript
js 弹出虚拟键盘修改密码的简单实例
Oct 10 Javascript
JavaScript实现汉字转换为拼音的库文件示例
Dec 22 Javascript
canvas 绘制圆形时钟
Feb 22 Javascript
Vue父子模版传值及组件传值的三种方法
Nov 27 Javascript
vue中如何使用ztree
Feb 06 Javascript
JS解析后台返回的JSON格式数据实例
Aug 06 Javascript
基于axios 解决跨域cookie丢失的问题
Sep 26 Javascript
一篇文章介绍redux、react-redux、redux-saga总结
May 23 Javascript
新手快速入门微信小程序组件库 iView Weapp
Jun 24 Javascript
vue的keep-alive用法技巧
Aug 15 Javascript
手动实现vue2.0的双向数据绑定原理详解
Feb 06 Vue.js
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
极典R601SW收音机
2021/03/02 无线电
PHP JSON格式数据交互实例代码详解
2011/01/13 PHP
win2003服务器使用WPS的COM组件的一些问题解决方法
2012/01/11 PHP
使用php发送有附件的电子邮件-(PHPMailer使用的实例分析)
2013/04/26 PHP
解析php5配置使用pdo
2013/07/03 PHP
php阻止页面后退的方法分享
2014/02/17 PHP
php检查日期函数checkdate用法实例
2015/03/19 PHP
PHP调用API接口实现天气查询功能的示例
2017/09/21 PHP
PHP实现统计所有字符在字符串中出现次数的方法
2017/10/17 PHP
PHP实现多图上传和单图上传功能
2018/05/17 PHP
PHP使用mysqli同时执行多条sql查询语句的实例
2019/03/22 PHP
在javascript将NodeList作为Array数组处理的方法
2010/07/09 Javascript
情人节专属 纯js脚本1k大小的3D玫瑰效果
2012/02/11 Javascript
Javascript验证Visa和MasterCard信用卡号的方法
2015/07/27 Javascript
JS中Array数组学习总结
2017/01/18 Javascript
JS实现简单表格排序操作示例
2017/10/07 Javascript
Vue下路由History模式打包后页面空白的解决方法
2018/06/29 Javascript
JavaScript之数组扁平化详解
2019/06/03 Javascript
代码块高亮可复制显示js插件highlight.js+clipboard.js整合
2021/02/15 Javascript
Python读取本地文件并解析网页元素的方法
2018/05/21 Python
python2 与 python3 实现共存的方法
2018/07/12 Python
Python os.access()用法实例
2019/02/18 Python
解决Python正则表达式匹配反斜杠''\''问题
2019/07/17 Python
Python tornado上传文件的功能
2020/03/26 Python
python 将视频 通过视频帧转换成时间实例
2020/04/23 Python
如何在Python3中使用telnetlib模块连接网络设备
2020/09/21 Python
css3背景_动力节点Java学院整理
2017/07/11 HTML / CSS
美国咖啡批发网站:Coffee.org
2017/06/29 全球购物
香港优质食材和美酒专门店:FoodWise
2017/09/01 全球购物
万户网络JAVA程序员岗位招聘笔试试卷
2013/01/08 面试题
办公室主任职责范文
2013/11/08 职场文书
个人素质的自我评价分享
2013/12/16 职场文书
元旦晚会上单位领导演讲稿
2014/01/05 职场文书
党的群众路线教育实践活动对照检查材料(个人)
2014/09/24 职场文书
关于有小孩的离婚协议书
2014/10/26 职场文书
车队安全员岗位职责
2015/02/15 职场文书