web自定义主题实现方案

需求背景

A用户:我喜欢亮色!B用户:我喜欢暗色系!...在实际的开发场景中,主题需求通常都是必不可少的,那咱们如何简单地实现咱们想要的效果呢!css

解决方案

话很少说,咱们先看一下demo效果html

实现思路:在页面的载体上自定义一个属性标签,用于记录切换不一样的主题,而后咱们的css文件会根据属性标签值的改变而加载不一样样式,来实现咱们切换主题的效果。干巴巴的描述,理解起来有点晦涩难懂,这里我以本身写的demo为例,和你们一块儿交流探讨。前端

<!doctype html>
<html lang="en">
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <style type="text/css">
</head>

<body customize-theme-style="dark">
  <app-root></app-root>
>
</body>

</html>
复制代码

目前不少单页面应用都会有一个index.html载体文件,路由<app-root></app-root>挂载在body节点上,因此咱们的页面组件都是挂载在body上,那么咱们在body节点上定义一个customize-theme-style="dark"属性标签用于记录主题状态的切换。接下来就是css会根据主题状态的切换来改变主题样式。 我这里CSS 预处理语言用的是less(若是你用的是sass,或者是其余的css预处理语言,思路都是相同的,语法上有些许不一样而已),在资源文件夹里建一个styles用于存放咱们的less样式文件,demo的编译环境是angular8.0,因此咱们要在angular.json脚手架文件声明咱们新建的资源文件(这里我就不详细说明配置过程了,不一样的前端框架,配置过程不一样,但框架历来不是技术实现的障碍,思路是同样的), json

如上图所示index.less用来定义主题样式以及覆盖第三方组件样式,theme.less用于定义全局的样式变量 在index.less中:

// 暗黑主题
[customize-theme-style='dark'] {
  //背景
  .alain-default {
    background: @background-color;
  }

  //表格
  .ant-table-thead>tr>th {
    background-color: @table-head-color;
    color: @font-color;
  }

  ......
}
// 亮色主题
[customize-theme-style='light'] {
  ......  
}
......
复制代码

主题状态的改变会加载不一样的css样式,接下来就是如何改变主题样式状态了sass

实现思路:咱们将用户设置的主题状态用localStorage存储在本地,若是用户没有设置,就加载默认主题。bash

//获取用户上次设置的主题
    this.themeSkin = this.storageService.getStorageValue('customize-theme');
    if (this.themeSkin) {
      //设置主题
      const body = document.getElementsByTagName('body')[0];
      body.setAttribute('customize-theme-style', this.themeSkin);
    }
    //切换主题
    changeSkin(skin) {
    const body = document.getElementsByTagName('body')[0];
    body.setAttribute('customize-theme-style', skin);
    //存储主题
    this.storageService.setStorageValue('customize-theme', skin);
  }
复制代码

完成以上步骤就基本上实现了自定义主题的切换需求。前端框架

然而事情并无这么简单!!!app

如今的框架都是提倡页面组件化,那么咱们本身写的组件怎么适配主题呢? 所谓的适配也就是让组件读取当前载体文件body节点(根节点)上的主题属性值,这个也不难作到。 举个栗子:框架

//自定义组件中的样式
:host-context([customize-theme-style='dark']) h4 {
   .mixin-font-color('dark');
 }
 
:host-context([customize-theme-style='light']) h4 {
   .mixin-font-color('light');
}

//index.less

.mixin-font-color(@a) when(@a='dark') {
  color: #ffffff;
}

.mixin-font-color(@a) when(@a='light') {
  color: #212121;
}

复制代码

编译后的css样式: [customize-theme-style='dark'][_nghost-fkw-c5] h4[_ngcontent-fkw-c5], [customize-theme-style='dark'] [_nghost-fkw-c5] h4[_ngcontent-fkw-c5] { color: #ffffff; }less

:host-context()伪类选择器能够读取最外层的挂载点上的属性,经过这一特性就能实现组件主题化了 (API:angular.io/guide/compo…) 这里就给咱们的组件中标题生成了一个惟一的样式。 至此,咱们的主题需求问题就迎刃而解了。 若是有什么疑问或者你有更好的解决方案,欢迎留言交流,谢谢~

相关文章
相关标签/搜索