Vue2.0实现炫酷的主题切换功能

这篇博客介绍了如何在Vue项目中实现动态切换主题色,包括创建不同主题的CSS文件,编写全局样式,页面样式引用,以及利用Vuex和localstorage实现主题状态的持久化,最后展示如何动态插入link标签来切换主题。
摘要由CSDN通过智能技术生成

请添加图片描述

效果展示

请添加图片描述

实现原理

通过写多套样式文件,在项目编译完成后动态更改link标签引入

实现过程

首先如果需要多套主题,必须要有多套样式文件,而样式文件又有很多写法,下面分享一下我的写法

主题css

首先我写了两套配色方案的css文件

这一步是关键,首先在 public 文件夹中创建一个theme文件夹用于存放主题配色css文件

之所以放在public文件夹中是防止webpack将其编辑打包了,后面我们引入需要用到

暗色和亮色配色方案

//dark.css
:root {
	--main-color: #505690;
	--bg-color-1: #282c34;
	--bg-color-2: #21252b;
	--bg-color-3: #4d5565;
	--text-color-1: #adb3c0;
	--animate-duration: 0.6s;
	--shadow: 2px 2px 5px 0 rgba(31, 31, 31, 0.7);
}

//light.css
:root {
	--main-color: #505690;
	--bg-color-1: #f9f9f9;
	--bg-color-2: #ffffff;
	--bg-color-3: #ececec;
	--text-color-1: rgb(50, 50, 50);
	--animate-duration: 0.6s;
	--shadow: 2px 2px 5px 0 rgba(31, 31, 31, 0.7);
}

全局样式

然后我写了一套直接在项目中引入的全局样式文件,在 main.js 中引入,下面放一部分示例代码,实际根据自己需求来

//global.scss
button,
div {
	font-size: 14px;
	color: var(--text-color-1);
	outline: none !important;
}
img {
	object-fit: cover !important;
}
/deep/.el-button {
	border-radius: 0.5rem !important;
}
#nprogress .bar {
	background: #505690 !important;
}
::-webkit-scrollbar {
	display: none;
}
.text-main {
	color: var(--text-main);
}
.bg-color-1 {
	background-color: var(--bg-color-1);
	color: #adb3c0;
}
.bg-color-2 {
	background-color: var(--bg-color-2);
	color: #adb3c0;
}
.bg-main {
	background-color: var(--main-color);
	color: white;
}

上面这套scss的要求就是你基本上全部颜色都要引用主题颜色里的颜色变量,已确保全局切换的时候能够覆盖到所有位置

页面文件

在实际的页面中样式的写法如下图(仅做示例,已删除相关业务代码)

// example.vue
<template>
  <div>
   <el-dialog
      :append-to-body="true"
      :visible.sync="show"
      :destroy-on-close="true"
      :close-on-click-modal="false"
      :title="title"
      width="30%"
    >
      <slot></slot>
    </el-dialog>
  </div>
</template>


<style lang='scss' scoped>
/deep/.el-dialog__body,
/deep/.el-dialog__header {
  background: var(--bg-color-1);
}
/deep/.el-dialog__title {
  color: var(--text-color-1);
}
</style>

动态引入

创建本地主题变量

首先你需要在localstroage里存储一个变量用于保存用户的主题类型,以便于用户进入网站时初始化样式,我用的是vuex+数据持久化实现的,所以我只需要在vuex中添加一个变量theme,在用户需要修改样式的时候触发changeTheme方法即可修改

Vuex的模块化与持久化

示例代码

export default new Vuex.Store({
    state: {
        'theme': 'light'
    },
    mutations: {
        changeTheme(state, theme) {
            state.theme = theme
        }
    },
    actions: {},
    modules: { ...initModules() },
    plugins: [
        createPersistedState({
            paths: ['theme'],
            storage: window.localStorage,
        }),
    ],
})

在App.vue中动态使用link引入主题样式

<!-- App.vue -->
<template>
    <div>
        <router-view></router-view>
    </div>
</template>

<script>
export default {
    watch: {
        '$store.state.theme': {
            handler() {
                this.changeTheme()
            },
            immediate: true
        }
    },
    components: {},
    mounted() {},

    methods: {
        changeTheme() {
            const theme = this.$store.state.theme
            const head = document.head
            // 遍历页面所有的link节点
            const links = document.getElementsByTagName('link')
            for (let i in links) {
                // 如果已有引入主题样式则删除
                if (links[i].href) {
                    if (
                        links[i].href.indexOf('dark.css') !== -1 ||
                        links[i].href.indexOf('light.css') !== -1
                    ) {
                        head.removeChild(links[i])
                    }
                }
            }
            // 创建新的主题节点插入head
            var link = document.createElement('link')
            link = Object.assign(link, {
                href: 'theme/' + theme + '.css',
                type: 'text/css',
                rel: 'stylesheet'
            })
            head.appendChild(link)
        }
    }
}
</script>

<style lang='scss' scoped>
</style>
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值