ant-design实现主题暗黑主题 和 亮色主题的 切换(实现网站黑白皮肤)

简介: 最近在使用vite+react + ant-design 来搭建个人站点,看到网上好多网站都实现了黑白皮肤的切换,并且ant-design帮我们实现了三套主题色,一个默认亮白色,暗黑主题和紧凑主题。于是我也想来弄一弄。最后还是实现了,打包后也是ok的。

最近在使用vite+react + ant-design 来搭建个人站点,看到网上好多网站都实现了黑白皮肤的切换,并且ant-design帮我们实现了三套主题色,一个默认亮白色,暗黑主题和紧凑主题。于是我也想来弄一弄。最后还是实现了,打包后也是ok的。


效果


20210519091646797.gif


思路


对于网站需要切换主题的话,一般有以下几种办法。


  • 使用css覆盖的方式,由于css基于后面的css覆盖前面的原理,所以这一点也是可以的。但是这一点对于使用less和scss的码友来说,貌似不是一个很好的方法


  • 由于less里面带有一个less.js的cdn,可以用来解析是html种使用less文件,但是这个需要注意使用的顺序,需要less的样式文件在前面,less.js的引用在后面,这个对于使用构建工具的同志来说不太友好,打包后less文件都不见了,直接使用路径肯定也是不行。


  • 社区成熟的两个库: antd-theme-webpack-plugin和antd-theme-generator,对于我的项目来说貌似都不怎么合适,首先:antd-theme-webpack-plugin这个库是基于webpack来的,我们都知道vite是在开发环境使用esbuild,生产环境使用的是roallup来进行打包。antd-theme-generator这个库的话,把less提升到了运行阶段,我们代码一般会进行打包压缩等,如果使用这个库的话就意味着需要配置less相关的静态资源不能被打包,不然会有问题。


基于上面的思路我做了以下的方法来进行尝试。


我的代码地址是(这个地址不会改动): https://github.com/cll123456/blog


项目做了以下调整:


将ant-design的两个主题,默认主题和暗黑主题引入到我自己的less文件中。然后对此就可以后序实现改动主题色,例如:成功,失败,警告等。如下:


20210519100628297.png


这个引入的顺序需要注意,后引入的变量会覆盖前面的。不会自定义的会不生效


20210519102431290.png


在我点击switch框的时候触发方法。做以下尝试


所有的尝试都是基于下面的第二步,也就是方法,这里面需要做啥事情


尝试一


改变方法的时候直接来动态引入less文件,这样在引入暗黑主题是可以实现的,但是从暗黑主题却切换不过来了。如下:


const handleSkin = (checked: boolean) => {
    if (checked) {
      // 明亮主题
       import('./../assets/style/index.less')
    } else {
      // 暗色主题
      import('./../assets/style/index.dark.less')
    }
  }


这个从白的可以切换到黑的原因是,黑色样式覆盖了前面白色的样式,但是如果你再一次覆盖却不行,我估计是选择器权重问题上,ant官方做了改动。如果需要从新切换回来也是有办法的,在明亮主题中直接window.location.reload(),这样是可以切换回来的,如下图:


20210519103535177.gif


这样虽然实现了功能,体验肯定是不好的,作为一名前端工程师,肯定是需要非常注重体验的,不然职业生涯的路可能就不会很长。


尝试二


  • 由于尝试一不行,然后我就往import动态引入这边考虑了,我考虑的方向是既然可以动态import引入,那么我可以再一次改变的时候把前一次引入的给remove掉么?


  • 但是我找遍了所有的文件,import导入的是无法remove掉的,import导入是现代浏览器里面的esm的语法。


  • 然后就去网上找各种方法,在ant-design pro中发现实现了这个功能,并且是无刷新的,然后就去gitup上看人家的源码。功夫不负有心人,然后发现人家是动态使用link引入css的方式来实现的,那么我也可以来通过link导入less文件来实现,并且使用less.js的cdn来进行解析。


添加一个addSkin的方法,毕竟需要导入文件,然后来查找原来是否存在,然后进行删除。


// 调用方法
const handleSkin = (checked: boolean) => {
    if (checked) {
      // 明亮主题
        addSkin("./../../src/assets/style/index.less")
    } else {
      // 暗色主题
     addSkin("./../../src/assets/style/index.dark.less")
    }
  }
// 添加皮肤的方法
function addSkin(path: string) {
  let head = document.getElementsByTagName("head")[0];
  const getLink = head.getElementsByTagName('link');
  // 查找link是否存在,存在的话需要删除dom
  if (getLink.length > 0) {
    for (let i = 0, l = getLink.length; i < l; i++) {
      if (getLink[i].getAttribute('data-type') === 'theme') {
        getLink[i].remove();
      }
    }
  }
  // 查找script是否存在
  const getScript = head.getElementsByTagName('script');
  if (getScript.length > 0) {
    for (let i = 0, l = getScript.length; i < l; i++) {
      if (getScript[i].getAttribute('data-type') === 'theme') {
        getScript[i].remove();
      }
    }
  }
  // 最后加入对应的主题和加载less的js文件
  let link = document.createElement("link");
  link.dataset.type = "theme";
  link.href = path;
  link.rel = "stylesheet";
  link.type = "text/css";
  head.appendChild(link);
  // 这个less.js一定要放到后面才行
  let script = document.createElement('script');
  script.type = 'text/javascript';
  script.dataset.type = 'theme';
  script.src = 'https://cdn.bootcdn.net/ajax/libs/less.js/4.1.1/less.js'
  head.appendChild(script)
}


这种方法是动态改变link标签的样式来实现的,在生产环境是没有任何问题,但是在开发环境就不行了,打包后路径不存在。肯定是不行的,接下来我就去找vite如何静态资源复制到打包的文件,方法找到了。但是我的less里面引用了antd里面的less,里面的也不用打包? 我觉得不太好,因此再一次放弃。


尝试三


既然直接使用less文件不行,那我可以使用css不,和ant-design pro里面一样的,我也来引用css文件,接下来就往这个方向。


我直接打印了,import dark from './xxxx'.less 发现既然是一个字符串。


2021051911082826.png


是编译好的字符串,那我直接使用style标签就好了。说干就往下干。


import dark from './../assets/style/index.dark.less'
import lighter from './../assets/style/index.less'
// 调用方法
const handleSkin = (checked: boolean) => {
    if (checked) {
      // 明亮主题
        addSkin(lighter)
    } else {
      // 暗色主题
     addSkin(dark)
    }
  }
// 添加皮肤的方法
function addSkin(content: string) {
  let head = document.getElementsByTagName("head")[0];
  const getStyle = head.getElementsByTagName('style');
  // 查找style是否存在,存在的话需要删除dom
  if (getStyle.length > 0) {
    for (let i = 0, l = getStyle.length; i < l; i++) {
      if (getStyle[i].getAttribute('data-type') === 'theme') {
        getStyle[i].remove();
      }
    }
  }
  // 最后加入对应的主题和加载less的js文件
  let styleDom = document.createElement("style");
  styleDom.dataset.type = "theme";
  styleDom.innerHTML = content;
  head.appendChild(styleDom);
}


  • 这里有一个细节就是,样式导入必须在顶部导入,不然vite会检测不到,不能使用动态导入,打包会经过treeshake去掉.


  • 其实这里还有一个问题,那就是css打包后会比较大,毕竟引入了两份,这个问题就留给码友了,自己去vite获取其他的构建工具(webpack, gulp等)上找静态资源太大怎么处理。


20210519111336588.png


总结


在真实的调试中肯定是不止这三遍尝试的,这里只记录走向成功的关键三步。More interest, less interests (多一些兴趣爱好的向往,少一些功名利禄的追求)

相关文章
|
设计模式 缓存 前端开发
一款清新优雅的中后台模板,内置丰富可配置的主题(强烈推荐)
Soybean Admin 是一个基于 Vue3、Vite3、TypeScript、NaiveUI、Pinia 和 UnoCSS 的清新优雅的中后台模版,它使用了最新的前端技术栈,内置丰富的主题配置,有着极高的代码规范,基于 mock 实现的动态权限路由,开箱即用的中后台前端解决方案,也可用于学习参考。
|
6月前
Nuxt3 实战 (八):优雅的实现暗黑主题模式
这篇文章介绍了在Nuxt3中实现暗黑模式的过程。首先推荐使用color-mode库来轻易实现暗黑模式切换,并通过pnpm命令安装@nuxtjs/color-mode依赖。然后在nuxt.config.ts配置文件中注入依赖,并根据项目实际情况自定义配置。接着通过toggleDark函数实现切换动画,并在需要的地方加载组件<ColorMode/>,从而达到最终效果。
180 3
Nuxt3 实战 (八):优雅的实现暗黑主题模式
|
6月前
首途第三十三套清新简约卡片风格蓝紫渐变色短视频模板 | 苹果CMSV10主题
首途第三十三套清新简约卡片风格蓝紫渐变色短视频模板 | 苹果CMSV10主题 我们的简约风格,以纯洁的白色和深邃的紫色为主色调,为您提供了一种清新、时尚的浏览体验。在这个简洁而美丽的界面中,您可以轻松畅享各种精彩短视频。我们专注于简单的设计,使用户能够轻松找到他们喜欢的内容,而不受繁杂的界面干扰。紫色的调性为网页增添了一抹神秘和优雅,让您在欣赏视频的同时感受到一份宁静和舒适。清晰的布局和直观的操作,让您可以更专注于视频内容,而不被复杂的功能所困扰
64 1
|
7月前
|
前端开发 iOS开发 MacOS
vscode自动跟随Mac或window系统系统切换主题色-白天用亮色主题、晚上用暗黑主题
vscode自动跟随Mac或window系统系统切换主题色-白天用亮色主题、晚上用暗黑主题
492 0
|
7月前
|
前端开发
自定义elementUI皮肤、色系、主题、主色调
自定义elementUI皮肤、色系、主题、主色调
|
搜索推荐
IDEA字体颜色、主题风格个性化 —— 手把手带你尽展个性
IDEA字体颜色、主题风格个性化 —— 手把手带你尽展个性
1231 0
|
缓存 容器
uniapp 中实现主题色配置切换
uniapp 中实现主题色配置切换
uniapp 中实现主题色配置切换
NetBeans主题配色方案加设置
1.网上下载主题的地址是:http://netbeansthemes.com/ **上面的主题我看了下但是感觉不太适合自己所以自己就仿照的设置了下下面我附上自己的配置信息 感兴趣的可以下载下来自己看下是否适合自己 链接为https://pan.
1703 0
Flutter 设置应用主题色和字体
App 开发过程中,肯定希望给用户带来一致的体验,这其中最基础的就是色调、字体保持一致。在 Flutter 中,可以设置全局的主题色调和字体,从而在其他页面引用主色调和字体,实现页面展示层面的一致。
1180 0
Flutter 设置应用主题色和字体