热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

vue动态换肤(自定义主题)

前言有时候一个项目的主题并不能满足所有人的审美,所以这个时候就需要换肤功能登场了。下面是一个换肤demo,思路很简单,定义一个全局css变量,然后在页面




前言



有时候一个项目的主题并不能满足所有人的审美, 所以这个时候就需要换肤功能登场了。
下面是一个换肤demo, 思路很简单,定义一个全局css变量,然后在页面根元素获取变量并动态修改这个变量值即可完成。



效果

效果图


具体实现


1.准备项目

准备一个含有lessvuex的项目


2.安装插件

yarn add style-resources-loader vue-cli-plugin-style-resources-loader -D

3.新建global.less

global.less用于定义全局变量设置全局默认样式


  • 路径: src/theme/global.less (先建一个theme目录)

// 默认主题 因为会放在rgba()中 所以只需要rgb这三个值 使用rgba的好处是一个主题可以根据透明度配置更多相似主题的颜色
@themeColor: var(--themeColor, 100, 149, 237);

4.配置vue.config.js

vue.config.js是项目可选的配置文件


  • 路径: 与 package.json 同级

const path = require("path");
module.exports = {
pluginOptions: {
"style-resources-loader": {
preProcessor: "less",
patterns: [
path.resolve(__dirname, "./src/theme/global.less"),
],
},
},
};

这里通过配置style-resources-loaderglobal.less设置的变量供项目中其他文件直接使用,而避免重复在每个样式文件中通过@import导入


5.新建model.js

model.js用于预设几套固定主题


  • 路径: src/theme/model.js

export const themes = {
/* 默认主题 */
default: {
backgroundColor: `${100},${149},${237}`
},
/* 暗黑主题 */
dark: {
backgroundColor: `${0},${0},${0}`
},
/* 鲜红主题 */
red: {
backgroundColor: `${247},${72},${72}`
},
/* 草绿主题 */
green: {
backgroundColor: `${59},${235},${115}`
}
};

这里我预设了四套固定主题


6.新建changeTheme.js

changeTheme.js用于定义修改主题的方法,修改样式与接收值来确定使用哪套主题的方法


  • 路径: src/theme/changeTheme.js

import {
themes
} from "./model";
// 修改样式
const changeStyle = (obj) => {
document.documentElement.style.setProperty(`--themeColor`, obj.backgroundColor);
};
// 改变主题的方法
export const setTheme = (themeName) => {
const haveTheme = themes[themeName];
// 有预设的主题名称
if (haveTheme) {
localStorage.setItem("primaryColor", haveTheme.backgroundColor);
changeStyle(haveTheme);
} else {
let haveTheme = {
backgroundColor: localStorage.getItem("primaryColor")
};
changeStyle(haveTheme);
}
};

7.动态换肤功能实现


  • 路径: src/view/Home.vue

<template>
<div class&#61;"home">
<header>温情keyheader>
<main>
<div class&#61;"box-item">
<div class&#61;"title">css动画-animationdiv>
<div class&#61;"content">
steps()可以传入两个参数&#xff0c;第一个是一个大于0的整数&#xff0c;他是将间隔动画等分成指定数目的小间隔动画&#xff0c;也就是指定每个阶段分为几步来展示动画
&#xff0c;然后根据第二个参数来决定显示效果。第二个参数设置后
其实和step-start&#xff0c;step-end同义&#xff0c;在分成的小间隔动画中判断显示效果。
div>
div>
<div class&#61;"box-item box2">
<div class&#61;"title">css动画-animationdiv>
<div class&#61;"content">
steps()可以传入两个参数&#xff0c;第一个是一个大于0的整数&#xff0c;他是将间隔动画等分成指定数目的小间隔动画&#xff0c;也就是指定每个阶段分为几步来展示动画
&#xff0c;然后根据第二个参数来决定显示效果。第二个参数设置后
其实和step-start&#xff0c;step-end同义&#xff0c;在分成的小间隔动画中判断显示效果。
div>
div>
main>
<footer><a href&#61;"https://www.wenqingkey.cn" style&#61;"text-decoration: none;color: #fff;">www.wenqingkey.cna>footer>
<div class&#61;"changeTheme" :style&#61;"{ right: openThemeCom &#61;&#61;&#61; true ? &#39;0&#39; : &#39;-310px&#39; }">
<div &#64;click&#61;"chooseTheme">{{ openThemeCom &#61;&#61;&#61; true ? "→" : "←" }}div>
<div &#64;click&#61;"setThemeHandle(&#39;default&#39;)">div>
<div &#64;click&#61;"setThemeHandle(&#39;dark&#39;)">div>
<div &#64;click&#61;"setThemeHandle(&#39;red&#39;)">div>
<div &#64;click&#61;"setThemeHandle(&#39;green&#39;)">div>
<div>
<input type&#61;"color" :value&#61;"defaultColor" &#64;input&#61;"chooseColor"/>
div>
div>
div>
template>
<script>
import { setTheme } from "../theme/changeTheme";
export default {
data() {
return {
// 选择主题组件开闭
openThemeCom: false,
};
},
computed: {
// 取色器 默认颜色
defaultColor() {
/* 将 rgb 转换为 hex 值 */
let color &#61; localStorage.getItem("primaryColor").split(&#39;,&#39;);
let hex &#61; "#" &#43; ((1 << 24) &#43; (Number(color[0]) << 16) &#43; (Number(color[1]) << 8) &#43; Number(color[2])).toString(16).slice(1);
// console.log(hex);
return hex;
}
},
created() {
this.initTheme();
},
methods: {
/* 初始化主题 */
initTheme() {
setTheme();
},
/* 选择主题组件显示/隐藏 */
chooseTheme() {
this.openThemeCom &#61; !this.openThemeCom;
},
/* 切换主题 */
setThemeHandle(val) {
setTheme(val);
},
/* 自定义主题 */
chooseColor(val) {
// hex 转换为 rgb
let hex &#61; val.target.value;
let r &#61; parseInt(&#39;0x&#39; &#43; hex.slice(1, 3));
let g &#61; parseInt(&#39;0x&#39; &#43; hex.slice(3, 5));
let b &#61; parseInt(&#39;0x&#39; &#43; hex.slice(5, 7));
let newPrimaryColor &#61; &#96;${r},${g},${b}&#96;;
// console.log(newPrimaryColor);
localStorage.setItem("primaryColor", newPrimaryColor);
setTheme();
},
},
};
script>
<style lang&#61;"less" scoped>
.home {
widows: 100vw;
height: 100vh;
display: grid;
grid-template-rows: 50px 1fr 50px;
background: #eee;
header,
footer
{
width: 100vw;
height: 50px;
background: rgba(&#64;themeColor, 1);
text-align: center;
line-height: 50px;
font-size: 1.6em;
color: #fff;
}
main {
padding: 10px;
.box-item {
border: 1px solid #555;
}
.box2 {
margin-top: 20px;
}
.title {
padding: 6px;
color: rgba(&#64;themeColor, 1);
font-size: 1.3em;
border-bottom: 1px solid #555;
}
.content {
padding: 10px;
background: rgba(&#64;themeColor, 0.2);
}
}
.changeTheme {
position: fixed;
bottom: 70px;
right: 0;
height: 40px;
width: 360px;
background: #fff;
display: grid;
grid-template-columns: repeat(6, 1fr);
column-gap: 5px;
transition: 0.3s ease;
div {
position: relative;
}
div::after {
display: inline-block;
width: 60px;
height: 20px;
text-align: center;
line-height: 20px;
position: absolute;
top: -22px;
left: 0;
}
div:nth-child(1) {
line-height: 40px;
text-align: center;
}
div:nth-child(2) {
background: rgb(100, 149, 237);
}
div:nth-child(2)::after {
content: "默认";
}
div:nth-child(3) {
background: rgb(0, 0, 0);
}
div:nth-child(3)::after {
content: "暗黑";
}
div:nth-child(4) {
background: rgb(247, 72, 72);
}
div:nth-child(4)::after {
content: "鲜红";
}
div:nth-child(5) {
background: rgb(59, 235, 115);
}
div:nth-child(5)::after {
content: "草绿";
}
div:nth-child(6)::after {
content: "自定义";
}
}
}
style>

源码地址

gitee源码地址







推荐阅读
  • 网络请求模块选择——axios框架的基本使用和封装
    本文介绍了选择网络请求模块axios的原因,以及axios框架的基本使用和封装方法。包括发送并发请求的演示,全局配置的设置,创建axios实例的方法,拦截器的使用,以及如何封装和请求响应劫持等内容。 ... [详细]
  • Java太阳系小游戏分析和源码详解
    本文介绍了一个基于Java的太阳系小游戏的分析和源码详解。通过对面向对象的知识的学习和实践,作者实现了太阳系各行星绕太阳转的效果。文章详细介绍了游戏的设计思路和源码结构,包括工具类、常量、图片加载、面板等。通过这个小游戏的制作,读者可以巩固和应用所学的知识,如类的继承、方法的重载与重写、多态和封装等。 ... [详细]
  • vue使用
    关键词: ... [详细]
  • Iamtryingtomakeaclassthatwillreadatextfileofnamesintoanarray,thenreturnthatarra ... [详细]
  • Spring源码解密之默认标签的解析方式分析
    本文分析了Spring源码解密中默认标签的解析方式。通过对命名空间的判断,区分默认命名空间和自定义命名空间,并采用不同的解析方式。其中,bean标签的解析最为复杂和重要。 ... [详细]
  • Webpack5内置处理图片资源的配置方法
    本文介绍了在Webpack5中处理图片资源的配置方法。在Webpack4中,我们需要使用file-loader和url-loader来处理图片资源,但是在Webpack5中,这两个Loader的功能已经被内置到Webpack中,我们只需要简单配置即可实现图片资源的处理。本文还介绍了一些常用的配置方法,如匹配不同类型的图片文件、设置输出路径等。通过本文的学习,读者可以快速掌握Webpack5处理图片资源的方法。 ... [详细]
  • 本文讨论了为什么在main.js中写import不会全局生效的问题,并提供了解决方案。在每一个vue文件中都需要写import语句才能使其生效,而在main.js中写import语句则不会全局生效。本文还介绍了使用Swal和sweetalert2库的示例。 ... [详细]
  • 本文介绍了OC学习笔记中的@property和@synthesize,包括属性的定义和合成的使用方法。通过示例代码详细讲解了@property和@synthesize的作用和用法。 ... [详细]
  • 在说Hibernate映射前,我们先来了解下对象关系映射ORM。ORM的实现思想就是将关系数据库中表的数据映射成对象,以对象的形式展现。这样开发人员就可以把对数据库的操作转化为对 ... [详细]
  • 本文讨论了一个关于cuowu类的问题,作者在使用cuowu类时遇到了错误提示和使用AdjustmentListener的问题。文章提供了16个解决方案,并给出了两个可能导致错误的原因。 ... [详细]
  • 在重复造轮子的情况下用ProxyServlet反向代理来减少工作量
    像不少公司内部不同团队都会自己研发自己工具产品,当各个产品逐渐成熟,到达了一定的发展瓶颈,同时每个产品都有着自己的入口,用户 ... [详细]
  • imx6ull开发板驱动MT7601U无线网卡的方法和步骤详解
    本文详细介绍了在imx6ull开发板上驱动MT7601U无线网卡的方法和步骤。首先介绍了开发环境和硬件平台,然后说明了MT7601U驱动已经集成在linux内核的linux-4.x.x/drivers/net/wireless/mediatek/mt7601u文件中。接着介绍了移植mt7601u驱动的过程,包括编译内核和配置设备驱动。最后,列举了关键词和相关信息供读者参考。 ... [详细]
  • web.py开发web 第八章 Formalchemy 服务端验证方法
    本文介绍了在web.py开发中使用Formalchemy进行服务端表单数据验证的方法。以User表单为例,详细说明了对各字段的验证要求,包括必填、长度限制、唯一性等。同时介绍了如何自定义验证方法来实现验证唯一性和两个密码是否相等的功能。该文提供了相关代码示例。 ... [详细]
  • 本文介绍了如何使用Express App提供静态文件,同时提到了一些不需要使用的文件,如package.json和/.ssh/known_hosts,并解释了为什么app.get('*')无法捕获所有请求以及为什么app.use(express.static(__dirname))可能会提供不需要的文件。 ... [详细]
  • JDK源码学习之HashTable(附带面试题)的学习笔记
    本文介绍了JDK源码学习之HashTable(附带面试题)的学习笔记,包括HashTable的定义、数据类型、与HashMap的关系和区别。文章提供了干货,并附带了其他相关主题的学习笔记。 ... [详细]
author-avatar
骆树真次_902
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有