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函数
Apr 09 Javascript
jQuery+ajax实现鼠标单击修改内容的方法
Jun 27 Javascript
javascript模拟评分控件实现方法
May 13 Javascript
jQuery实现checkbox全选的方法
Jun 10 Javascript
Javascript中匿名函数的调用与写法实例详解(多种)
Jan 26 Javascript
bootstrapvalidator之API学习教程
Jun 29 Javascript
详解Vue学习笔记入门篇之组件的内容分发(slot)
Jul 17 Javascript
vuejs父子组件之间数据交互详解
Aug 09 Javascript
浅谈webpack对样式的处理
Jan 05 Javascript
Vue 组件(component)教程之实现精美的日历方法示例
Jan 08 Javascript
vue.js实现图书管理功能
Sep 24 Javascript
vue print.js打印支持Echarts图表操作
Nov 13 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生成二维码的几种方式整理及使用实例
2013/06/03 PHP
php中如何判断一个网页请求是ajax请求还是普通请求
2013/08/10 PHP
PHP5中使用mysqli的prepare操作数据库的介绍
2019/03/18 PHP
javascript 常用方法总结
2009/06/03 Javascript
javascript 进阶篇1 正则表达式,cookie管理,userData
2012/03/14 Javascript
node.js中的http.response.addTrailers方法使用说明
2014/12/14 Javascript
JavaScript数据绑定实现一个简单的 MVVM 库
2016/04/08 Javascript
JS跨域解决方案之使用CORS实现跨域
2016/04/14 Javascript
jQuery实现圣诞节礼物动画案例解析
2016/12/25 Javascript
微信小程序 图片宽度自适应的实现
2017/04/06 Javascript
详谈Node.js之操作文件系统
2017/08/29 Javascript
AngularJS实时获取并显示密码的方法
2018/02/06 Javascript
Vue用v-for给src属性赋值的方法
2018/03/03 Javascript
详解vue指令与$nextTick 操作DOM的不同之处
2018/08/02 Javascript
浅析vue-router中params和query的区别
2019/12/24 Javascript
jquery实现垂直手风琴导航栏
2020/02/18 jQuery
9个JavaScript日常开发小技巧
2020/10/06 Javascript
关于IDEA中的.VUE文件报错 Export declarations are not supported by current JavaScript version
2020/10/17 Javascript
[01:25]DOTA2自定义游戏灵园鬼域等你踏足
2015/10/30 DOTA
[58:25]VP vs RNG 2019国际邀请赛小组赛 BO2 第一场 8.15
2019/08/17 DOTA
python中的对象拷贝示例 python引用传递
2014/01/23 Python
线程和进程的区别及Python代码实例
2015/02/04 Python
基于python的字节编译详解
2017/09/20 Python
如何在python中使用selenium的示例
2017/12/26 Python
python实现将读入的多维list转为一维list的方法
2018/06/28 Python
python绘制立方体的方法
2018/07/02 Python
Python生命游戏实现原理及过程解析(附源代码)
2019/08/01 Python
python动态文本进度条的实例代码
2020/01/22 Python
python要安装在哪个盘
2020/06/15 Python
python实现猜拳游戏项目
2020/11/30 Python
Elemental Herbology官网:英国美容品牌
2019/04/27 全球购物
读书活动总结范文
2014/04/26 职场文书
大学四年个人总结
2015/03/03 职场文书
钢铁是怎样炼成的读书笔记
2015/06/29 职场文书
2019年大学生职业生涯规划书最新范文
2019/03/25 职场文书
Python基础 括号()[]{}的详解
2021/11/07 Python