当前位置:Gxlcms > JavaScript > Vue 换肤的示例实践

Vue 换肤的示例实践

时间:2021-07-01 10:21:17 帮助过:2人阅读

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

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

CSS切换

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

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

  1. .side-bar {
  2. background: linear-gradient(#B7A3FF, #879FFF) !important;
  3. }
  4. .side-bar .account-info {
  5. background: #8981D8 !important;
  6. }

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

  1. colors: [{
  2. themeId: 1,
  3. familyPrimary: '#B7A3FF',
  4. familySecondary: '#879FFF',
  5. sideBarTop: '#8981D8'
  6. }, {
  7. themeId: 2,
  8. familyPrimary: '#FDC5C5',
  9. familySecondary: '#F070A0',
  10. sideBarTop: '#E7829F'
  11. }, {
  12. themeId: 3,
  13. familyPrimary: '#414D6C',
  14. familySecondary: '#2D1E3C',
  15. sideBarTop: '#423C50'
  16. }]

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

  1. getFile(`/static/theme.css`)
  2. .then(({data}) => {
  3. let style = getStyleTemplate(data)
  4. })
  5. function getStyleTemplate (data) {
  6. const colorMap = {
  7. '#B7A3FF': 'familyPrimary',
  8. '#879FFF': 'familySecondary',
  9. '#8981D8': 'sideBarTop'
  10. }
  11. Object.keys(colorMap).forEach(key => {
  12. const value = colorMap[key]
  13. data = data.replace(new RegExp(key, 'ig'), value)
  14. })
  15. return data
  16. }

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

  1. getFile(`/static/theme.css`)
  2. .then(({data}) => {
  3. let style = getStyleTemplate(data)
  4. writeNewStyle(style, this.color)
  5. })
  6. function writeNewStyle (originalStyle, colors) {
  7. let oldEl = document.getElementById('temp-style')
  8. let cssText = originalStyle
  9. Object.keys(colors).forEach(key => {
  10. cssText = cssText.replace(new RegExp(key, 'ig'), colors[key])
  11. })
  12. const style = document.createElement('style')
  13. style.innerText = cssText
  14. style.id = 'temp-style'
  15. oldEl ? document.head.replaceChild(style, oldEl) : document.head.appendChild(style)
  16. }

图标切换

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

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

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

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

  1. @font-face {
  2. font-family: 'icomoon';
  3. src: url('../assets/fonts/icomoon.eot?vpkwno');
  4. src: url('../assets/fonts/icomoon.eot?vpkwno#iefix') format('embedded-opentype'),
  5. url('../assets/fonts/icomoon.ttf?vpkwno') format('truetype'),
  6. url('../assets/fonts/icomoon.woff?vpkwno') format('woff'),
  7. url('../assets/fonts/icomoon.svg?vpkwno#icomoon') format('svg');
  8. font-weight: normal;
  9. font-style: normal;
  10. }
  11. [class^="icon-"], [class*=" icon-"] {
  12. /* use !important to prevent issues with browser extensions that change fonts */
  13. font-family: 'icomoon' !important;
  14. speak: none;
  15. font-style: normal;
  16. font-weight: normal;
  17. font-variant: normal;
  18. text-transform: none;
  19. line-height: 1;
  20. vertical-align: sub;
  21. /* Better Font Rendering =========== */
  22. -webkit-font-smoothing: antialiased;
  23. -moz-osx-font-smoothing: grayscale;
  24. }
  25. .icon-edit:before {
  26. content: "\e900";
  27. }

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

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

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

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

图片切换

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

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

placeholderMixin

  1. let callback
  2. const placeholderMixin = {
  3. data () {
  4. return {
  5. placeholderWoman: '',
  6. placeHolderNoReply: '',
  7. placeHolderNothing: ''
  8. }
  9. },
  10. created () {
  11. let themeId = localStorage.getItem('themeId')
  12. let theme = themeId2Name(themeId)
  13. this.setThemeValue(theme)
  14. callback = (theme) => {
  15. this.setThemeValue(theme)
  16. }
  17. bus.$on('changeTheme', callback)
  18. },
  19. destroyed () {
  20. bus.$off('changeTheme', callback)
  21. },
  22. methods: {
  23. setThemeValue (theme) {
  24. this.placeholderWoman = require(`@/assets/placeholder_woman_${theme}.svg`)
  25. this.placeHolderNoReply = require(`@/assets/icon_noreply_${theme}.svg`)
  26. this.placeHolderNothing = require(`@/assets/icon_nothing_${theme}.svg`)
  27. }
  28. }
  29. }

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

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

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

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

人气教程排行