当前位置: 首页 > article >正文

【sass+css变量实现换肤】

文章目录

  • 需求
  • 思路
  • 实现
    • 组件
    • 手动换肤
    • 动态换肤

需求

假如你最近在开发一套组件库,如何让用户可以换肤呢?

  1. 使用者可以固定自定义主题色、基本色等相关主题
  2. 也支持动态切换,可以只切换单个颜色,也支持全部切换

思路

定义sass或者css变量,所有的颜色都用变量定义,当用户自定义颜色时,通过覆盖或者修改变量完成换肤

组件库css样式设计注意点:

  1. 用bem方式命名:块、元素、修饰符
  2. 结构和皮肤分离

实现

组件

这里拿两个组件举例子,一个是src/myui/mybutton.vue:

<template>
  <button class="button button-primary">
    <slot></slot>
  </button>
</template>
<script>
export default {
  name: "mybutton",
};
</script>

另一个是src/myui/myheader.vue:

<template>
<!-- 定义结构和皮肤的类分离开 -->
  <header class="header background-theme">12312</header>
</template>

 
<script>
export default {
  name: "myheader",
};
</script>

手动换肤

定义默认的颜色变量文件src/myui/css/variable.scss:

$theme-color:red !default;// 默认皮肤都要加default,如果不加default,后面可能无法覆盖这个变量
$button-primary:blue !default;

在main.js中引入默认样式:

import { createApp } from 'vue'
import App from './App.vue'
import myui from "./myui"
import "./variable.scss"
createApp(App).use(myui).mount('#app')

使用:

<script setup>
import HelloWorld from "./components/HelloWorld.vue";
import TheWelcome from "./components/TheWelcome.vue";
import { onMounted, ref } from "vue";
</script>

<template>
  <div class="myclass">
    <myheader></myheader>
    <mybutton>1231</mybutton>
  </div>
</template>

<style scoped>
header {
  line-height: 1.5;
}

.logo {
  display: block;
  margin: 0 auto 2rem;
}

@media (min-width: 1024px) {
  header {
    display: flex;
    place-items: center;
    padding-right: calc(var(--section-gap) / 2);
  }

  .logo {
    margin: 0 2rem 0 0;
  }

  header .wrapper {
    display: flex;
    place-items: flex-start;
    flex-wrap: wrap;
  }
}
</style>

src/myui/css/index.scss中定义样式:

 @import "./variable.scss";// 引入
 .header{
  width: 100%;
  min-height: 30px;
 }
 .button{
  min-width: 40px;
 }
 .background-theme{
   background-color: $theme-color;//使用变量
 }
 .button-primary{
  background-color: $button-primary;
 }

如果是手动换肤,接下来可以新建一个新皮肤的scss文件src/myindex.scss:

// 编写变量来覆盖变量
$theme-color:pink;
$button-primary:yellow;

@import "@/myui/css/index.scss"// 引入组件库的样式文件,一定要写在最后

然后改变main.js中的引用:

import { createApp } from 'vue'
import App from './App.vue'
import myui from "./myui"
import "./myindex.scss"// 改变引用
createApp(App).use(myui).mount('#app')

动态换肤

如果想实现动态换肤,那么需要改写变量和属性的生成方式,src/myui/css/variable.scss的内容改为:

//  $theme-color:red !default;// 默认皮肤都要加default,如果不加default,后面可能无法覆盖这个变量
//  $button-primary:blue !default;

// 将变量的声明方式改写成集合的形式
$themes:(// 在scss中,()用来定义对象
    default-theme:(// default-theme是这个对象的属性,这个属性的值也是一个对象
        //这一套主题所有的相关颜色
        theme-color:red,
        button-primary:blue
    )
)!default;

样式的生成通过方法来生成,方法定义在src/myui/css/mixin.scss:

@mixin get-backcolor($color){// 在scss中,通过@mixin定义一个方法
   // scss中使用@each进行循环,这里循环variable.scss中的$themes对象,因此$themename指default-theme,$theme为default-theme的值
   @each $themename,$theme in $themes {
      [data-skin='#{$themename}'] &{// 如果html标签上面的data-skin属性等于主题的名字,就为当前元素的background-color设置某个颜色,颜色的获取通过map-get方法获取
         // 就是通过map对象获取值,map对象就是default-theme的值,$color是这个方法传进来的变量,但实际上是default-theme的值(对象)的键,
         // 所以map-get($theme,$color)取的是:default-theme的值(对象)的$color指向的键的值
         background-color: map-get($theme,$color);
      }
   }
}
// 如果要写完整的话,还需要定义生成字体颜色的方法,但是本文用生成背景颜色的方法作为示例
// @mixin get-fontcolor(){

// }

之后属性由方法来生成,src/myui/css/index.scss中定义样式:

 @import "./variable.scss";
 @import "./mixin.scss";
 .header{
  width: 100%;
  min-height: 30px;
 }
 .button{
  min-width: 40px;
 }
 .background-theme{
   @include get-backcolor('theme-color')// 在scss中使用@include调用方法
 }
 .button-primary{
   @include get-backcolor('button-primary')
 }

为根节点设置data-skin属性,在src/App.vue的script标签中添加代码:

onMounted(() => {
  window.document.documentElement.setAttribute('data-skin','default- theme')
})

在src/myindex.scss中自定义两套皮肤:

$themes:(
    skin1:(
        theme-color:var(--data-theme-color,pink),
        button-primary:var(--data-button-primary,blue),
    ),
    skin2:(
        theme-color:var(--data-theme-color,black),
        button-primary:var(--data-button-primary,green),
    )
);
@import "@/myui/css/index.scss"

在src/App.vue中添加按钮,点击后进行皮肤切换

<script setup>
import HelloWorld from "./components/HelloWorld.vue";
import TheWelcome from "./components/TheWelcome.vue";
import { onMounted, ref } from "vue";
onMounted(() => {
  window.document.documentElement.setAttribute('data-skin','skin1')
})
function changeskin(name) {
  window.document.documentElement.setAttribute('data-skin',name)
 }
</script>

<template>
  <div>
      <button @click="changeskin('skin1')">皮肤1</button>
      <button @click="changeskin('skin2')">皮肤2</button>
      <myheader></myheader>
      <mybutton>1231</mybutton>
  </div>
</template>

<style scoped>
header {
  line-height: 1.5;
}

.logo {
  display: block;
  margin: 0 auto 2rem;
}

@media (min-width: 1024px) {
  header {
    display: flex;
    place-items: center;
    padding-right: calc(var(--section-gap) / 2);
  }

  .logo {
    margin: 0 2rem 0 0;
  }

  header .wrapper {
    display: flex;
    place-items: flex-start;
    flex-wrap: wrap;
  }
}
</style>

这样,我们就利用scss完成了换肤:首先借助scss的方法,修改变量的定义的形式,通过方法生成样式的属性,根据html上的属性名来决定用哪一套变量,从而生成不同的颜色。接下来配合css变量


http://www.kler.cn/a/512008.html

相关文章:

  • 【博客之星2024年度总评选】年度回望:我的博客之路与星光熠熠
  • http://noi.openjudge.cn/——4.7算法之搜索——【169:The Buses】
  • 软路由系统iStoreOS 一键安装 docker compose
  • [手机Linux] 七,NextCloud优化设置
  • 如何设置HTTPS站点防御?
  • Docker部署MySQL 5.7:持久化数据的实战技巧
  • Maven项目中没有.iml文件
  • 编辑器Vim基本模式和指令 --【Linux基础开发工具】
  • 深入解析MIMIC IV数据库中 labevents 和 chatevents 数据表的区别与联系
  • .Net Core微服务入门全纪录(五)——Ocelot-API网关(下)
  • 定制setsockopt只设置一次实现指定sock的永久quickack
  • 如何在Nginx服务器上配置访问静态文件目录并提供文件下载功能
  • 实用技巧:快速修复电脑dxgidebug.dll缺失
  • 什么是报文的大端和小端,有没有什么记忆口诀?
  • WPF基础 | 初探 WPF:理解其核心架构与开发环境搭建
  • javaEE初阶(计算机是如何工作的(2) )
  • 用Zig开发Web后端独特好处
  • k8s 部署kafka单机和集群
  • 使用 Parcel 和 NPM 脚本进行打包
  • 【大数据】机器学习------聚类
  • 常见的图形库概览-03-D3.js 入门例子
  • 计算机系统原理:一些断言
  • Transformer详解:Attention机制原理
  • Vue2:el-tree用scope slot为每一个节点添加一个鼠标悬浮时出现的右对齐的按钮
  • C# 事件(Event)详解
  • C++和OpenGL实现3D游戏编程【连载21】——父物体和子物体模式实现