17.vue自定义主题颜色皮肤
17.vue 自定义主题
1.安装需要的相关依赖
npm i element-theme -g
npm i element-theme-chalk -D
2.初始化变量文件
et -i
项目根目录下生成
打卡此文件
修改变量
编译主题
et
3.引入主题
在main.js
中引入
import Vue from 'vue'import App from './App.vue'import router from './router'import store from './store'// 导入字体图标库import './assets/fonts/iconfont.css'import './plugins/element.js'import 'element-ui/lib/theme-chalk/index.css'import '../theme/index.css'import ElementUI from 'element-ui'// 导入全局样式表import './assets/scss/global.scss'// 导入全局接口入口文件import api from './api/index'// 导入国际化i18nimport VueI18n from 'vue-i18n'// 导入全局mockimport './mock'Vue.config.productionTip = falseVue.use(VueI18n) // 通过插件的形式挂载Vue.use(ElementUI)const i18n = new VueI18n({ locale: 'zh-CN', // 语言标识 // this.$i18n.locale // 通过切换locale的值来实现语言切换 messages: { 'zh-CN': require('./assets/lang/zh'), // 中文语言包 'en-US': require('./assets/lang/en') // 英文语言包 }})// 将导入的接口文件全局挂载在vue全局上Vue.prototype.$api = apinew Vue({ i18n, router, store, render: h => h(App)}).$mount('#app')
4.封装动态换肤色ThemePicker.vue组件
参考大神:
博客园:https://www.cnblogs.com/dengqichang/p/10364455.html
大神的博客地址
- ThemePicker.vue内容
<template> <el-color-picker class="theme-picker" popper-class="theme-picker-dropdown" v-model="theme" :size="size"> </el-color-picker></template><script>const version = require('element-ui/package.json').version // element-ui version from node_modulesconst ORIGINAL_THEME = '#409EFF' // default colorexport default { name: 'ThemePicker', props: { default: { // 初始化主题,可由外部传入 type: String, // default: '#EB815B' default: '' localStorage.getItem('tremePackers') '' }, size: { // 初始化主题,可由外部传入 type: String, default: 'small' } }, data() { return { chalk: '', // content of theme-chalk css theme: ORIGINAL_THEME, showSuccess: true // 是否弹出换肤成功消息 } }, mounted() { if (this.default != null) { this.theme = this.default this.$emit('onThemeChange', this.theme) this.showSuccess = false } }, watch: { theme(val, oldVal) { if (typeof val !== 'string') return const themeCluster = this.getThemeCluster(val.replace('#', '')) const originalCluster = this.getThemeCluster(oldVal.replace('#', '')) const getHandler = (variable, id) => { return () => { const originalCluster = this.getThemeCluster(ORIGINAL_THEME.replace('#', '')) const newStyle = this.updateStyle(this[variable], originalCluster, themeCluster) let styleTag = document.getElementById(id) if (!styleTag) { styleTag = document.createElement('style') styleTag.setAttribute('id', id) document.head.appendChild(styleTag) } styleTag.innerText = newStyle } } const chalkHandler = getHandler('chalk', 'chalk-style') if (!this.chalk) { const url = `https://unpkg.com/element-ui@${version}/lib/theme-chalk/index.css` this.getCSSString(url, chalkHandler, 'chalk') } else { chalkHandler() } const styles = [].slice.call(document.querySelectorAll('style')).filter(style => { const text = style.innerText return new RegExp(oldVal, 'i').test(text) && !/Chalk Variables/.test(text) }) styles.forEach(style => { const { innerText } = style if (typeof innerText !== 'string') return style.innerText = this.updateStyle(innerText, originalCluster, themeCluster) }) // 响应外部操作 this.$emit('onThemeChange', val) // 存入localStorage localStorage.setItem('tremePackers', val) if (this.showSuccess) { this.$notify.success({ title: this.$t('lang.tip'), message: this.$t('lang.optSuccess') }) } else { this.showSuccess = true } } }, methods: { updateStyle(style, oldCluster, newCluster) { let newStyle = style oldCluster.forEach((color, index) => { newStyle = newStyle.replace(new RegExp(color, 'ig'), newCluster[index]) }) return newStyle }, getCSSString(url, callback, variable) { const xhr = new XMLHttpRequest() xhr.onreadystatechange = () => { if (xhr.readyState === 4 && xhr.status === 200) { this[variable] = xhr.responseText.replace(/@font-face{[^}] }/, '') callback() } } xhr.open('GET', url) xhr.send() }, getThemeCluster(theme) { const tintColor = (color, tint) => { let red = parseInt(color.slice(0, 2), 16) let green = parseInt(color.slice(2, 4), 16) let blue = parseInt(color.slice(4, 6), 16) if (tint === 0) { // when primary color is in its rgb space return [red, green, blue].join(',') } else { red = Math.round(tint * (255 - red)) green = Math.round(tint * (255 - green)) blue = Math.round(tint * (255 - blue)) red = red.toString(16) green = green.toString(16) blue = blue.toString(16) return `#${red}${green}${blue}` } } const shadeColor = (color, shade) => { let red = parseInt(color.slice(0, 2), 16) let green = parseInt(color.slice(2, 4), 16) let blue = parseInt(color.slice(4, 6), 16) red = Math.round((1 - shade) * red) green = Math.round((1 - shade) * green) blue = Math.round((1 - shade) * blue) red = red.toString(16) green = green.toString(16) blue = blue.toString(16) return `#${red}${green}${blue}` } const clusters = [theme] for (let i = 0; i <= 9; i ) { clusters.push(tintColor(theme, Number((i / 10).toFixed(2)))) } clusters.push(shadeColor(theme, 0.1)) return clusters } }}</script><style>.theme-picker .el-color-picker__trigger { vertical-align: middle;}.theme-picker-dropdown .el-color-dropdown__link-btn { display: none;}</style>
5.导入组件
<template> <header> <!-- 头部左侧导航折叠按钮 --> <div> <i class="el-icon-s-fold" v-show="!isCollapse" @click="collapseMenu"></i> <i class="el-icon-s-unfold" v-show="isCollapse" @click="collapseMenu"></i> </div> <!-- 右侧工具栏部分 --> <div class="opt-wrapper"> <!-- 主题选择 --> <div class="theme-picker"> <theme-picker></theme-picker> </div> <!-- 语言切换 --> <div class="lang"> <el-dropdown :hide-on-click="false" @command="changeLang"> <span class="el-dropdown-link">{{ lang }}<i class="el-icon-arrow-down el-icon--right"></i></span> <el-dropdown-menu slot="dropdown"> <el-dropdown-item command="zh-CN">{{ $t('lang.chinese') }}</el-dropdown-item> <el-dropdown-item command="en-US">{{ $t('lang.engLish') }}</el-dropdown-item> </el-dropdown-menu> </el-dropdown> </div> <!-- 是否全屏 --> <div class="fullScreen"> <i class="iconfont icon-caozuo-quanping-shousuo" v-show="isFullscreen" @click="screen"></i> <i class="iconfont icon-icon-GIS_quanping" v-show="!isFullscreen" @click="screen"></i> </div> <!-- 用户信息、退出登录 --> <div> <el-dropdown :hide-on-click="false" @command="handleCommand"> <span class="el-dropdown-link"> <img :src="avatar" alt="" class="avatar"/></span> <el-dropdown-menu slot="dropdown"> <el-dropdown-item command="userinfo"><i class="el-icon-info"></i>{{ $t('lang.personal') }}</el-dropdown-item> <el-dropdown-item command="logout"><i class="el-icon-switch-button"></i>{{ $t('lang.logout') }}</el-dropdown-item> </el-dropdown-menu> </el-dropdown> </div> </div> </header></template><script>// 导入选择主题组件import ThemePicker from '@/components/ThemePicker/ThemePicker'import { mapState } from 'vuex'import screenfull from 'screenfull'export default { components: { ThemePicker }, data() { return { isFullscreen: false, // 是否是全屏 avatar: require('@/assets/images/admin-logo.jpg') } }, computed: { ...mapState({ isCollapse: state => state.tab.isCollapse, lang: state => state.header.lang }) }, created() { // 获取刷新之前的语言信息 const sessionLang = JSON.parse(sessionStorage.getItem('currentLang')) console.log(sessionLang) if (sessionLang !== null) { // 获取到存储的路由列表之后,将信息利用vuex进行存储 if (sessionLang.currentLang === 'EngLish') { this.$i18n.locale = 'en-US' this.$store.commit('changeLang', 'en-US') } if (sessionLang.currentLang === '中文') { this.$i18n.locale = 'zh-CN' this.$store.commit('changeLang', 'zh-CN') } } }, mounted() { // 刷新之前存储当前语言信息 window.addEventListener('beforeunload', e => { sessionStorage.setItem( 'currentLang', JSON.stringify({ currentLang: this.lang }) ) }) }, methods: { // 退出方法 handleCommand(command) { if (command === 'logout') { sessionStorage.clear() sessionStorage.removeItem('tabs') this.$router.push('/login') window.location.reload() } if (command === 'userinfo') { this.$router.push('/userinfo') const userinfo = { path: '/userinfo', name: 'userinfo', label: '个人信息', icon: 'info' } this.$store.commit('selectMenu', userinfo) } this.$message.success('click on item ' command) }, // 控制左侧导航栏开启/关闭事件 collapseMenu() { this.$store.commit('collapseMenu') }, // 切换语言 changeLang(command) { if (command === 'zh-CN') { this.$i18n.locale = 'zh-CN' } if (command === 'en-US') { this.$i18n.locale = 'en-US' } this.$store.commit('changeLang', command) }, // 控制是否是全屏还是非全屏 screen() { // 如果不允许进入全屏,发出不允许提示 // if (!screenfull.enabled) { // this.$message('您的浏览器不能全屏') // return false // } screenfull.toggle() this.isFullscreen = !screenfull.isFullscreen // console.log(screenfull.isFullscreen) // this.$message.success('全屏啦') } }}</script><style lang="scss" scoped>@import '~@/assets/scss/common/header.scss';</style>
6.效果演示
赞 (0)