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 相关文章推荐
非常好的js代码
Jun 27 Javascript
Jquery实现页面加载时弹出对话框代码
Apr 19 Javascript
如何实现chrome浏览器关闭页面时弹出“确定要离开此面吗?”
Mar 05 Javascript
Javascript类型转换的规则实例解析
Feb 23 Javascript
jQuery AJAX timeout 超时问题详解
Jun 21 Javascript
Angular 理解module和injector,即依赖注入
Sep 07 Javascript
js正则表达式验证密码强度【推荐】
Mar 03 Javascript
原生javascript移动端滑动banner效果
Mar 10 Javascript
JS获取填报扩展单元格控件的值的解决办法
Jul 14 Javascript
Angular2+如何去除url中的#号详解
Dec 20 Javascript
解决vue 按钮多次点击重复提交数据问题
May 10 Javascript
javascript数组常见操作方法实例总结【连接、添加、删除、去重、排序等】
Jun 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
ecshop 批量上传(加入自定义属性)
2012/03/20 PHP
详解 PHP加密解密字符串函数附源码下载
2015/12/18 PHP
一个实用的php验证码类
2017/07/06 PHP
JavaScript 三种创建对象的方法
2009/10/16 Javascript
jQuery 核心函数以及jQuery对象
2010/03/23 Javascript
再说AutoComplete自动补全之实现原理
2011/11/05 Javascript
js history对象简单实现返回和前进
2013/10/30 Javascript
AngularJS入门教程之学习环境搭建
2014/12/06 Javascript
js实现鼠标感应图片展示的方法
2015/02/27 Javascript
基于jQuery插件jqzoom实现的图片放大镜效果示例
2017/01/23 Javascript
node结合swig渲染摸板的方法
2018/04/11 Javascript
vue通过数据过滤实现表格合并
2020/11/30 Javascript
vue父子模板传值问题解决方法案例分析
2020/02/26 Javascript
如何利用node转发请求详解
2020/09/17 Javascript
python实现根据窗口标题调用窗口的方法
2015/03/13 Python
日常整理python执行系统命令的常见方法(全)
2015/10/22 Python
Python编程实现及时获取新邮件的方法示例
2017/08/10 Python
200 行python 代码实现 2048 游戏
2018/01/12 Python
python+tkinter编写电脑桌面放大镜程序实例代码
2018/01/16 Python
python实现Windows电脑定时关机
2018/06/20 Python
python爬虫框架scrapy实现模拟登录操作示例
2018/08/02 Python
Python并发之多进程的方法实例代码
2018/08/15 Python
Windows下安装Scrapy
2018/10/17 Python
Django 外键的使用方法详解
2019/07/19 Python
python和php哪个更适合写爬虫
2020/06/22 Python
KIKO美国官网:意大利的平价彩妆品牌
2017/05/16 全球购物
洛杉矶时尚女装系列:J.ING US
2019/03/17 全球购物
Java中有几种方法可以实现一个线程?用什么关键字修饰同步方法?stop()和suspend()方法为何不推荐使用?
2015/08/04 面试题
考试作弊被抓检讨书
2014/01/10 职场文书
关于元旦的广播稿
2014/02/16 职场文书
8和9的加减法教学反思
2014/05/01 职场文书
乔布斯斯坦福大学演讲稿
2014/05/23 职场文书
装修活动策划方案
2014/08/27 职场文书
2014年乡镇安全生产工作总结
2014/12/02 职场文书
2016十一国庆节慰问信
2015/12/01 职场文书
redis数据结构之压缩列表
2022/03/21 Redis