一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第22天,点击查看活动详情。
说起换肤功能,前端肯定不陌生,其实就是颜色值的更换,实现方式有很多,也各有优缺点
一般来说换肤的需求分为两种:
-
一种是几种可供选择的颜色/主题样式,进行选择切换,这种可供选择的主题切换不会很多
-
另一种是需要自定义色值,或者通过取色板取色,可供选择的范围就很大了
对于可供选择的颜色/主题样式换肤的实现
一个全局class控制样式切换
切换的时候js控制样式的切换
<!-- 中心 -->
<template>
动态获取父级class名称,进行一个父级class的多次定义
<div :class="className">
<div class="switch" v-on:click="chang()">
{{ className == "box" ? "开灯" : "关灯" }}
</div>
</div>
</template>
<script>
export default {
name: "Centre",
data() {
return {
className: "box"
};
},
methods: {
// 改变class
chang() {
this.className === "box"
? (this.className = "boxs")
: (this.className = "box");
}
},
};
</script>
<style lang="scss">
当class为box 使用witch的css
@import "./style/witch.scss";
当class为boxs 使用black的css
@import "./style/black.scss";
.switch {
position: fixed;
top: 4px;
right: 10px;
z-index: 50;
width: 60px;
height: 60px;
background: #fff;
line-height: 60px;
border-radius: 20%;
}
</style>
复制代码
每个css文件样式大致相同,只是最外层的父级不一样,分别为.box 和.boxs
JS改变href属性值切换样式表,例如
<link id="skincolor" href="skin-default.css" rel="stylesheet" type="text/css">
document.getElementById('#skincolor').href = 'skin-red.css';
复制代码
这种方式需要维护几个主题样式表,js点击切换的时候通过改变css样式表链接来实现。 例如这个 demo
这种实现对于,颜色和主题多了的时候,维护起来就很麻烦,需要同时维护 n 个样式文件,并且使用JS改变href属性会带来加载延迟,样式切换不流畅,体验也不好。
但如果是有包含不同复杂背景图片切换的时候,这种方式可以实现,但其他如下面要说的css变量 less modifyVars 就无法实现了
HTML 的 rel 属性下的 alternate 实现:
示例:
<link href="reset.css" rel="stylesheet" type="text/css">
<link href="default.css" rel="stylesheet" type="text/css" title="Default Style">
<link href="fancy.css" rel="alternate stylesheet" type="text/css" title="Fancy">
<link href="basic.css" rel="alternate stylesheet" type="text/css" title="Basic">
复制代码
所有样式表都可分为3类:
- 没有title属性,rel属性值仅仅是stylesheet的无论如何都会加载并渲染,如reset.css;
- 有title属性,rel属性值仅仅是stylesheet的作为默认样式CSS文件加载并渲染,如default.css;
- 有title属性,rel属性值同时包含alternate stylesheet的作为备选样式CSS文件加载,默认不渲染,如red.css和green.css;
alternate意味备用,相当于是 css 预加载进来备用,所以不会有上面那种切换延时
但怎么用呢?禁用掉? developer.mozilla.org/en-US/docs/…
link 的 disabled 属性
使用JavaScript代码修改元素DOM对象的disabled值为false,可以让默认不渲染的CSS开始渲染。实现 demo
对于制定动态色值换肤的实现
如果是要实现动态换肤,自定义色值,那上面的几种方式就不适合了。
先看下已有的实现有哪些方法
Element-UI 有换肤功能 示例预览
实现原理: 官方解释
- 先把默认主题文件中涉及到颜色的 CSS 值替换成关键词:github.com/ElementUI/t…
- 根据用户选择的主题色生成一系列对应的颜色值:github.com/ElementUI/t…
- 把关键词再换回刚刚生成的相应的颜色值:github.com/ElementUI/t…
- 直接在页面上加 style 标签,把生成的样式填进去:github.com/ElementUI/t…
看这个实现,还是比较麻烦的,想看看还有没有更优雅的方法来实现
Ant Design 的更换主题色功能是用 less 提供的 modifyVars 的方式进行覆盖变量来实现。
less的 modifyVars方法
modifyVars方法是是基于 less 在浏览器中的编译来实现。所以在引入less文件的时候需要通过link方式引入,然后基于less.js中的方法来进行修改变量
less.modifyVars({
'@themeColor': 'blue'
});
复制代码
link方式引入主题色文件
<link rel="stylesheet/less" type="text/css" href="./src/less/public.less" />
复制代码
更改主题色事件
// color 传入颜色值
handleColorChange (color) {
less.modifyVars({ // 调用 `less.modifyVars` 方法来改变变量值'
@themeColor':color
})
.then(() => {
console.log('修改成功');
});
};
复制代码
如果发现项目运行报错如下:
.bezierEasingMixin();
^
Inline JavaScript is not enabled. Is it set in your options?
复制代码
那可能是没有开启 javascriptEnabled:true
在webpack配置里开启
{
test: /\.less$/,
loader: 'less-loader',
options: {
javascriptEnabled: true
}
},
复制代码
less方法仅限于用less的项目才能使用,查了下sass是没有类似 less.modifyVars 这种方法的。
那有没有通用一点的方法呢?于是就有了
css 变量方法
如果项目里用的不是less, 那么还是用css的方法,通用且容易操作,使用css变量来进行主题色的修改,替换主题色变量,然后用setProperty来进行动态修改
用法就是给变量加--前缀,涉及到主题色的都改成var(--themeColor)这种方式
可以看下兼容性
大部分主流浏览器还是支持的,而且主要是操作起来够简便。
用法举例:
body{
--themeColor:#000;
}
复制代码
使用:
.main{
color: var(--themeColor);
}
复制代码
要修改主题色的话:
document.body.style.setProperty('--themeColor', '#ff0000');
复制代码
参考:
www.zhangxinxu.com/wordpress/2…
scss动态切换变量
我自己是分为了2个主要文件来做的
- _variable.scss 变量管理文件 var()为css3中提出的声明样式变量的方法 var(属性名,属性值)注意属性值不能是字符串
// 主题切换
$bgColor:var(--backgroundColor,rgb(255,255,255));
$fontColor:var(--fonntColor,rgb(0,0,0));
$bgmColor:var(--backgroundMColor,rgb(238,238,238));
$tableColor:var(--tableColor,rgb(218,218,218));
$borderColor:var(--borderColor,rgb(238,238,238));
$tablesColor:var(--tablesColor,rgb(255,255,255));
$inputColor:var(--inputColor,rgb(255,255,255))
复制代码
创建的_variable.scss 文件我在vue.config.js进行了一个全局的配置,没有在组件中引入
复制代码
css: {
loaderOptions: {
// 此文件为主题切换文件
sass: {
prependData: `@import "./src/styles/_variable.scss";`,
},
},
},
复制代码
- publicStyle.js 这个方法可以去修改var定义的变量 document.getElementsByTagName("body")[0].style.setProperty("属性名", "替换的属性值f");
// 主题切换
const cut = (cutcheack) => {
document.getElementsByTagName("body")[0].style.setProperty("--backgroundColor", cutcheack ? "#121212" : "#fff");
document.getElementsByTagName("body")[0].style.setProperty("--fonntColor", cutcheack ? "#cecece" : "#333");
document.getElementsByTagName("body")[0].style.setProperty("--backgroundMColor", cutcheack ? "#333" : "#eee");
document.getElementsByTagName("body")[0].style.setProperty("--tableColor", cutcheack ? "#000" : "#d8d8d8");
document.getElementsByTagName("body")[0].style.setProperty("--tablesColor", cutcheack ? "#222" : "#fff");
document.getElementsByTagName("body")[0].style.setProperty("--inputColor", cutcheack ? "#666" : "#fff");
document.getElementsByTagName("body")[0].style.setProperty("--borderColor", cutcheack ? "#666" : "#fff");
};
export default cut;
复制代码
组件中使用
<!-- 首页 -->
<template>
<div class='home'>
<el-switch v-model="cutcheack" active-color="#333" inactive-color="#13ce66" active-text="主题" @change="switchs"></el-switch>
</div>
</template>
<script>
import cut from "../../utils/publicStyle.js";
export default {
name: "Home",
data() {
return {
cutcheack: false, //主题切换
};
},
methods: {
// 左侧导航隐藏或显示
// 切换主题
switchs() {
cut(this.cutcheack);
},
},
};
</script>
<style lang='scss' scope>
.home {
height: 100%;
width: 100%;
background:$bgColor;
.el-container {
height: 100%;
color:$fontColor;
}
}
</style>
复制代码